libui 0.0.6 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0214c682062d1e669d2ec2df579d91466b2d0330205231d00734e3d9b21fc57
4
- data.tar.gz: 2bce2e4f6edf26bd2442e7205ef10ad59529f1e16f2a88aa0a282cb61d623ced
3
+ metadata.gz: f5856ad97384408635e170c1ea252dc3dbdfa1ba3955bfc8b8c1ac2c29585ac1
4
+ data.tar.gz: 67a9b78e39b61805afca932fc80365b59e068493f2da937c57b03e1500a2adf5
5
5
  SHA512:
6
- metadata.gz: f700b08bb46f282b7298f7530bbbade2a59fcde144e54af97bb01a1766a98b3a133b10e064cd62a69621e2d61ff9d587bff17d850f96bb23b4e5c2ee101f97a7
7
- data.tar.gz: 8571472b2ceb6fa2cd5d6627fce64c896e2ae651012fd8d949f9a94a6cf70dc48df6af7f379652c956b3b1e5e6725fb14465d616abdae776e9ec635c0c4150f9
6
+ metadata.gz: 5204e35c1c0f4b0c5f8acd69a4a1d76b6482a1fb298376c99ce29632a202c1340a39e017b68c563b4539a74e721b1611cd3a732b4a9983ef2a0fb3eef7a80b3c
7
+ data.tar.gz: 8fb83fe3d145646bacb598dc88413364d534493f275c2e0ef637e9718908fe895796a1cb95cdb56f6c6d24b216f23ed68a7812a0c0978a5c700a014ecd0d1573
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
- # libui
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
 
@@ -11,27 +11,38 @@
11
11
  gem install libui
12
12
  ```
13
13
 
14
- The libui gem uses the standard Ruby library [Fiddle](https://github.com/ruby/fiddle) to call C functions. And this gem contains the official release of the libui shared library version 4.1 for Windows, Mac, and Linux. That means there is no need to install anything other than this gem.
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
 
18
27
  ```ruby
19
28
  require 'libui'
29
+
20
30
  UI = LibUI
21
31
 
22
32
  UI.init
23
33
 
24
- main_window = UI.new_window('hello world', 300, 200, 1)
25
- UI.window_on_closing(main_window) do
26
- puts 'Bye Bye'
27
- UI.control_destroy(main_window)
28
- UI.quit
29
- 0
30
- end
34
+ main_window = UI.new_window('hello world', 200, 100, 1)
31
35
 
32
36
  button = UI.new_button('Button')
37
+
33
38
  UI.button_on_clicked(button) do
34
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
35
46
  0
36
47
  end
37
48
 
@@ -46,10 +57,11 @@ See [examples](https://github.com/kojix2/libui/tree/main/examples) directory.
46
57
 
47
58
  ### General Rules
48
59
 
60
+ Compared to original libui written in C,
61
+
49
62
  * The method names are snake_case.
50
63
  * If the last argument is nil, it can be omitted.
51
64
  * You can pass a block as a callback.
52
- * Please return 0 explicitly in the block.
53
65
  * The block will be converted to a Proc object and added to the last argument.
54
66
  * Even in that case, it is possible to omit the last argument nil.
55
67
 
@@ -57,6 +69,7 @@ See [examples](https://github.com/kojix2/libui/tree/main/examples) directory.
57
69
 
58
70
  * At the moment, it is not object-oriented.
59
71
  * Instead of providing a half-baked object-oriented approach, leave it as is.
72
+ * [A list of DSLs for LibUI.](https://github.com/kojix2/LibUI/wiki/DSL-for-LibUI)
60
73
 
61
74
  ### How to use fiddle pointers?
62
75
 
@@ -92,35 +105,79 @@ UI.font_button_on_changed(font_button) do
92
105
  end
93
106
  ```
94
107
 
108
+ * Callbacks
109
+ * In Ruby/Fiddle, C callback function is written as an object of
110
+ `Fiddle::Closure::BlockCaller` or `Fiddle::Closure`.
111
+ In this case, you need to be careful about Ruby's garbage collection.
112
+ If the function object is collected, memory will be freed
113
+ and a segmentation violation will occur when the callback is invoked.
114
+
115
+ ```ruby
116
+ # to a local variable to prevent it from being collected by GC.
117
+ handler.MouseEvent = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
118
+ handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
119
+ handler.DragBroken = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
120
+ ```
121
+
95
122
  ### How to create an executable (.exe) on Windows
96
123
 
97
124
  OCRA (One-Click Ruby Application) builds Windows executables from Ruby source code.
98
125
  * https://github.com/larsch/ocra/
99
126
 
127
+ In order to build a exe with Ocra, include 3 DLLs from ruby_builtin_dlls folder:
128
+
129
+ ```sh
130
+ ocra examples/control_gallery.rb ^
131
+ --dll ruby_builtin_dlls/libssp-0.dll ^
132
+ --dll ruby_builtin_dlls/libgmp-10.dll ^
133
+ --dll ruby_builtin_dlls/libffi-7.dll ^
134
+ --gem-all=fiddle ^
135
+ ```
136
+
137
+ Add additional options below if necessary.
138
+
139
+ ```sh
140
+ --window ^
141
+ --add-all-core ^
142
+ --chdir-first ^
143
+ --icon assets\app.ico ^
144
+ --verbose ^
145
+ --output out\gallery.exe
146
+ ```
147
+
100
148
  ## Development
101
149
 
102
150
  ```sh
103
151
  git clone https://github.com/kojix2/libui
104
152
  cd libui
105
153
  bundle install
106
- bundle exec rake vendor:all
154
+ bundle exec rake vendor:all_x64 # download shared libraries for all platforms
107
155
  bundle exec rake test
108
156
  ```
109
157
 
110
- Use the following rake tasks to download the libui binary files and save them in the vendor directory.
158
+ You can use the following rake tasks to download the shared library required for your platform.
111
159
 
112
160
  `rake -T`
113
161
 
114
162
  ```
115
- rake vendor:all # Download libui.so, libui.dylib, and libui.dll to ve...
116
- rake vendor:linux # Download libui.so for Linux to vendor directory
117
- rake vendor:mac # Download libui.dylib for Mac to vendor directory
118
- rake vendor:windows # Download libui.dll for Windows to vendor directory
163
+ rake vendor:all_x64 # Download libui.so, libui.dylib, and libui.dll to...
164
+ rake vendor:linux_x64 # Download libui.so for Linux to vendor directory
165
+ rake vendor:linux_x86 # Download libui.so for Linux to vendor directory
166
+ rake vendor:mac_x64 # Download libui.dylib for Mac to vendor directory
167
+ rake vendor:windows_x64 # Download libui.dll for Windows to vendor directory
168
+ rake vendor:windows_x86 # Download libui.dll for Windows to vendor directory
119
169
  ```
120
170
 
171
+ For example, If you are using a 32-bit (x86) version of Ruby on Windows, type `rake vendor:windows_x86`.
172
+
173
+ Or Set environment variable `LIBUIDIR` to specify the path to the shared library.
174
+
121
175
  ## Contributing
122
176
 
123
- Bug reports and pull requests are welcome on GitHub at https://github.com/kojix2/libui.
177
+ Would you like to add your commits to libui?
178
+ * Please feel free to send us your [pull requests](https://github.com/kojix2/libui/pulls).
179
+ * Small corrections, such as typofixes, are appreciated.
180
+ * Did you find any bugs? Write it in the [issues](https://github.com/kojix2/LibUI/issue) section!
124
181
 
125
182
  ## Acknowledgement
126
183
 
data/lib/libui/ffi.rb CHANGED
@@ -1,85 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fiddle/import'
4
-
5
- module Fiddle
6
- # Change the Function to hold a little more information.
7
- # FIXME: Give inner_function a better name.
8
- class Function
9
- attr_accessor :inner_functions, :argtype
10
- end
11
-
12
- module Importer
13
- def parse_signature(signature, tymap = nil)
14
- tymap ||= {}
15
- ret, func, args = split_signature(signature)
16
- symname = func
17
- ctype = parse_ctype(ret, tymap)
18
- inner_funcs = [] # Added
19
- argtype = split_arguments(args).collect.with_index do |arg, idx| # Added with_index
20
- # Check if it is a function pointer or not
21
- if arg =~ /\(\*.*\)\(.*\)/ # Added
22
- # From the arguments, create a notation that looks like a function declaration
23
- # int(*f)(int *, void *) -> int f(int *, void *)
24
- func_arg = arg.sub('(*', ' ').sub(')', '') # Added
25
- # Use Fiddle's parse_signature method again.
26
- inner_funcs[idx] = parse_signature(func_arg) # Added
27
- end # Added
28
- parse_ctype(arg, tymap)
29
- end
30
- # Added inner_funcs. Original method return only 3 values.
31
- [symname, ctype, argtype, inner_funcs]
32
- end
33
-
34
- # refactored
35
- def split_signature(signature)
36
- case compact(signature)
37
- when /^(?:[\w*\s]+)\(\*(\w+)\((.*?)\)\)(?:\[\w*\]|\(.*?\));?$/
38
- ret = TYPE_VOIDP
39
- func = Regexp.last_match(1)
40
- args = Regexp.last_match(2)
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
- else
46
- raise("can't parse the function prototype: #{signature}")
47
- end
48
- [ret, func, args]
49
- end
50
-
51
- def extern(signature, *opts)
52
- symname, ctype, argtype, inner_funcs = parse_signature(signature, type_alias)
53
- opt = parse_bind_options(opts)
54
- f = import_function(symname, ctype, argtype, opt[:call_type])
55
-
56
- f.inner_functions = inner_funcs # Added
57
- f.argtype = argtype # Added
58
-
59
- name = symname.gsub(/@.+/, '')
60
- @func_map[name] = f
61
- # define_method(name){|*args,&block| f.call(*args,&block)}
62
- begin
63
- /^(.+?):(\d+)/ =~ caller.first
64
- file = Regexp.last_match(1)
65
- line = Regexp.last_match(2).to_i
66
- rescue StandardError
67
- file, line = __FILE__, __LINE__ + 3
68
- end
69
- module_eval(<<-EOS, file, line)
70
- def #{name}(*args, &block)
71
- @func_map['#{name}'].call(*args,&block)
72
- end
73
- EOS
74
- module_function(name)
75
- f
76
- end
77
- end
78
- end
4
+ require_relative 'fiddle_patch'
79
5
 
80
6
  module LibUI
81
7
  module FFI
82
8
  extend Fiddle::Importer
9
+ extend FiddlePatch
83
10
 
84
11
  begin
85
12
  dlload LibUI.ffi_lib
@@ -284,7 +211,20 @@ module LibUI
284
211
  try_extern 'void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data)'
285
212
  try_extern 'uiRadioButtons *uiNewRadioButtons(void)'
286
213
 
287
- # uiDateTimePicker # Fixme: struct tm
214
+ # uiDateTimePicker
215
+
216
+ # time.h
217
+ TM = struct [
218
+ 'int tm_sec',
219
+ 'int tm_min',
220
+ 'int tm_hour',
221
+ 'int tm_mday',
222
+ 'int tm_mon',
223
+ 'int tm_year',
224
+ 'int tm_wday',
225
+ 'int tm_yday',
226
+ 'int tm_isdst'
227
+ ]
288
228
 
289
229
  try_extern 'void uiDateTimePickerTime(uiDateTimePicker *d, struct tm *time)'
290
230
  try_extern 'void uiDateTimePickerSetTime(uiDateTimePicker *d, const struct tm *time)'
@@ -0,0 +1,79 @@
1
+ module LibUI
2
+ module FiddlePatch
3
+ def parse_signature(signature, tymap = nil)
4
+ tymap ||= {}
5
+ ctype, func, args = case compact(signature)
6
+ when /^(?:[\w\*\s]+)\(\*(\w+)\((.*?)\)\)(?:\[\w*\]|\(.*?\));?$/
7
+ [TYPE_VOIDP, Regexp.last_match(1), Regexp.last_match(2)]
8
+ when /^([\w\*\s]+[*\s])(\w+)\((.*?)\);?$/
9
+ [parse_ctype(Regexp.last_match(1).strip, tymap), Regexp.last_match(2), Regexp.last_match(3)]
10
+ else
11
+ raise("can't parserake the function prototype: #{signature}")
12
+ end
13
+ symname = func
14
+ callback_argument_types = {} # Added
15
+ argtype = split_arguments(args).collect.with_index do |arg, idx| # Added with_index
16
+ # Check if it is a function pointer or not
17
+ if arg =~ /\(\*.*\)\(.*\)/ # Added
18
+ # From the arguments, create a notation that looks like a function declaration
19
+ # int(*f)(int *, void *) -> int f(int *, void *)
20
+ func_arg = arg.sub('(*', ' ').sub(')', '') # Added
21
+ # Use Fiddle's parse_signature method again.
22
+ callback_argument_types[idx] = parse_signature(func_arg) # Added
23
+ end
24
+ parse_ctype(arg, tymap)
25
+ end
26
+ # Added callback_argument_types. Original method return only 3 values.
27
+ [symname, ctype, argtype, callback_argument_types]
28
+ end
29
+
30
+ def extern(signature, *opts)
31
+ symname, ctype, argtype, callback_argument_types = parse_signature(signature, type_alias)
32
+ opt = parse_bind_options(opts)
33
+ func = import_function(symname, ctype, argtype, opt[:call_type])
34
+
35
+ # callback_argument_types
36
+ func.instance_variable_set(:@callback_argument_types,
37
+ callback_argument_types) # Added
38
+ # attr_reader
39
+ def func.callback_argument_types
40
+ @callback_argument_types
41
+ end
42
+
43
+ # argument_types
44
+ # Ruby 2.7 Fiddle::Function dose not have @argument_types
45
+ # Ruby 3.0 Fiddle::Function has @argument_types
46
+ if func.instance_variable_defined?(:@argument_types)
47
+ # check if @argument_types are the same
48
+ if func.instance_variable_get(:@argument_types) != argtype
49
+ warn "#{symname} func.argument_types:#{func.argument_types} != argtype #{argtype}"
50
+ end
51
+ else
52
+ func.instance_variable_set(:@argument_types, argtype)
53
+ end
54
+ # attr_reader
55
+ def func.argument_types
56
+ @argument_types
57
+ end
58
+
59
+ name = symname.gsub(/@.+/, '')
60
+ @func_map[name] = func
61
+ # define_method(name){|*args,&block| f.call(*args,&block)}
62
+ begin
63
+ /^(.+?):(\d+)/ =~ caller.first
64
+ file = Regexp.last_match(1)
65
+ line = Regexp.last_match(2).to_i
66
+ rescue StandardError
67
+ file, line = __FILE__, __LINE__ + 3
68
+ end
69
+ module_eval(<<-EOS, file, line)
70
+ def #{name}(*args, &block)
71
+ @func_map['#{name}'].call(*args,&block)
72
+ end
73
+ EOS
74
+ module_function(name)
75
+ func
76
+ end
77
+ end
78
+ private_constant :FiddlePatch
79
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LibUI
4
+ module LibUIBase
5
+ FFI.func_map.each_key do |original_method_name|
6
+ name = Utils.convert_to_ruby_method(original_method_name)
7
+ func = FFI.func_map[original_method_name]
8
+
9
+ define_method(name) do |*args, &blk|
10
+ # Assume that block is the last argument.
11
+ args << blk if blk
12
+
13
+ # The proc object is converted to a Closure::BlockCaller object.
14
+ args.map!.with_index do |arg, idx|
15
+ if arg.is_a?(Proc)
16
+ # The types of the function arguments are recorded beforehand.
17
+ # See the monkey patch in ffi.rb.
18
+ callback = Fiddle::Closure::BlockCaller.new(
19
+ *func.callback_argument_types[idx][1..2], &arg
20
+ )
21
+ # Protect from GC
22
+ # See https://github.com/kojix2/LibUI/issues/8
23
+ receiver = args[0]
24
+ if receiver.instance_variable_defined?(:@callbacks)
25
+ receiver.instance_variable_get(:@callbacks) << callback
26
+ else
27
+ receiver.instance_variable_set(:@callbacks, [callback])
28
+ end
29
+ callback
30
+ else
31
+ arg
32
+ end
33
+ end
34
+
35
+ # Make it possible to omit the last nil. This may be an over-optimization.
36
+ siz = func.argument_types.size - 1
37
+ args[siz] = nil if args.size == siz
38
+
39
+ FFI.public_send(original_method_name, *args)
40
+ end
41
+ end
42
+ end
43
+
44
+ private_constant :LibUIBase
45
+ end
data/lib/libui/utils.rb CHANGED
@@ -8,7 +8,7 @@ module LibUI
8
8
  # Converting camel case to underscore case in ruby
9
9
  # https://stackoverflow.com/questions/1509915/converting-camel-case-to-underscore-case-in-ruby#1509939
10
10
  def underscore(str)
11
- str.gsub(/::/, '/')
11
+ str.gsub(/::/, '/') # Maybe we don't need it.
12
12
  .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
13
13
  .gsub(/([a-z\d])([A-Z])/, '\1_\2')
14
14
  .tr('-', '_')
data/lib/libui/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LibUI
4
- VERSION = '0.0.6'
4
+ VERSION = '0.0.10'
5
5
  end
data/lib/libui.rb CHANGED
@@ -10,14 +10,7 @@ module LibUI
10
10
  attr_accessor :ffi_lib
11
11
  end
12
12
 
13
- lib_name = case RbConfig::CONFIG['host_os']
14
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
15
- 'libui.dll'
16
- when /darwin|mac os/
17
- 'libui.dylib'
18
- else
19
- 'libui.so'
20
- end
13
+ lib_name = "libui.#{RbConfig::CONFIG['SOEXT']}"
21
14
 
22
15
  self.ffi_lib = if ENV['LIBUIDIR'] && !ENV['LIBUIDIR'].empty?
23
16
  File.expand_path(lib_name, ENV['LIBUIDIR'])
@@ -26,45 +19,17 @@ module LibUI
26
19
  end
27
20
 
28
21
  require_relative 'libui/ffi'
22
+ require_relative 'libui/libui_base'
29
23
 
30
- class << self
31
- FFI.func_map.each_key do |original_method_name|
32
- name = Utils.convert_to_ruby_method(original_method_name)
33
- func = FFI.func_map[original_method_name]
34
-
35
- define_method(name) do |*args, &blk|
36
- # Assume that block is the last argument.
37
- args << blk if blk
38
-
39
- # The proc object is converted to a Closure::BlockCaller object.
40
- args.map!.with_index do |arg, idx|
41
- if arg.is_a?(Proc)
42
- # The types of the function arguments are recorded beforehand.
43
- # See the monkey patch in ffi.rb.
44
- Fiddle::Closure::BlockCaller.new(*func.inner_functions[idx][1..2], &arg)
45
- else
46
- arg
47
- end
48
- end
49
-
50
- # Make it possible to omit the last nil. This may be an over-optimization.
51
- siz = func.argtype.size - 1
52
- args[siz] = nil if args.size == siz
24
+ extend LibUIBase
53
25
 
54
- FFI.public_send(original_method_name, *args)
55
- end
56
- end
26
+ class << self
27
+ def init(opt = FFI::InitOptions.malloc)
28
+ i = super(opt)
29
+ return if i.size.zero?
57
30
 
58
- module CustomMethods
59
- def init(opt = FFI::InitOptions.malloc)
60
- i = super(opt)
61
- unless i.size.zero?
62
- warn 'error'
63
- warn UI.free_init_error(init)
64
- end
65
- end
31
+ warn 'error'
32
+ warn UI.free_init_error(init)
66
33
  end
67
-
68
- prepend CustomMethods
69
34
  end
70
35
  end
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.6
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-22 00:00:00.000000000 Z
11
+ date: 2021-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -91,6 +91,8 @@ files:
91
91
  - README.md
92
92
  - lib/libui.rb
93
93
  - lib/libui/ffi.rb
94
+ - lib/libui/fiddle_patch.rb
95
+ - lib/libui/libui_base.rb
94
96
  - lib/libui/utils.rb
95
97
  - lib/libui/version.rb
96
98
  - vendor/LICENSE
@@ -117,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
119
  - !ruby/object:Gem::Version
118
120
  version: '0'
119
121
  requirements: []
120
- rubygems_version: 3.1.4
122
+ rubygems_version: 3.2.22
121
123
  signing_key:
122
124
  specification_version: 4
123
125
  summary: Ruby bindings to libui