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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9942c95097af2b3c542472fa3e144e040cf3f9c0ef253e891d87b79b93070e77
4
- data.tar.gz: a69a733f1cd1dd2274c601422a2cb3a5b91d762055d73fc3e9e9f59e6f11c919
3
+ metadata.gz: dbb5362886495f17bf74055bf1ad4cbc96bb7f0e4518e8db0b18f9572559adf2
4
+ data.tar.gz: 19040d301c6cb135a3e5ef1270f211f48f007f02ec3e5fe7edcbc3be03f275da
5
5
  SHA512:
6
- metadata.gz: 47d42cfbc47996ad411f0ba9e6634378fa2bd088d84bc4179698c4ad3c049a7ce8e75218c8fd93538362d01961c9ca4d278aa2c60a5074a1fea532d4b22841b8
7
- data.tar.gz: 25c390450f42ff51ee05a9f5c7c9409c16860ac1ae3351e0d85aa30ad1d753f7cad2e1091ff9193bdf85cb21d77c344fbe1acdb5e429746e9d69574b59388379
6
+ metadata.gz: 27a0c320d8592b2e6a6531b66ed0de3a83a3f606058d16469af530d0633a02d2d13e848e5ca4dd8d6c184015449a2ba56b4eb6c7e63ede1ccb7bfa6d447b5f1b
7
+ data.tar.gz: '033190ef229e3f567db9c7a7d338da4107072a6120e79c928a5e03dffcca922ffe75ac76f631fda810133cd6316d6af55ea234eb3fce214540fe1e92fd7d6eaf'
data/README.md CHANGED
@@ -1,37 +1,182 @@
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
 
10
10
  ```sh
11
- gem install libui --pre
11
+ gem install libui
12
12
  ```
13
13
 
14
- The libui gem package contains the official release of the libui shared library version 4.1 for Windows, Mac, and Linux.
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
- * Keep it simple.
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
- Bug reports and pull requests are welcome on GitHub at https://github.com/kojix2/libui.
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
- attr_accessor :inner_functions, :argtype
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
- ret, func, args = split_signature(signature)
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
- ctype = parse_ctype(ret, tymap)
18
- inner_funcs = [] # Added
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 =~ /\(\*.*\)\(.*\)/ # Added
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(')', '') # Added
32
+ func_arg = arg.sub('(*', ' ').sub(')', '') # Added
25
33
  # Use Fiddle's parse_signature method again.
26
- inner_funcs[idx] = parse_signature(func_arg) # Added
27
- end # Added
34
+ callback_argument_types[idx] = parse_signature(func_arg) # Added
35
+ end
28
36
  parse_ctype(arg, tymap)
29
37
  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
- 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, inner_funcs = parse_signature(signature, type_alias)
43
+ symname, ctype, argtype, callback_argument_types = parse_signature(signature, type_alias)
53
44
  opt = parse_bind_options(opts)
54
- f = import_function(symname, ctype, argtype, opt[:call_type])
45
+ func = import_function(symname, ctype, argtype, opt[:call_type])
55
46
 
56
- f.inner_functions = inner_funcs # Added
57
- f.argtype = argtype # Added
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] = f
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
- f
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 # Fixme: struct tm
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)'
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LibUI
4
- VERSION = '0.0.5.alpha'
4
+ VERSION = '0.0.9'
5
5
  end
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 = case RbConfig::CONFIG['host_os']
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
- # Convert snake_case to CamelCase.
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(*func.inner_functions[idx][1..2], &arg)
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.argtype.size - 1
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
- unless i.size.zero?
68
- warn 'error'
69
- warn UI.free_init_error(init)
70
- end
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.5.alpha
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: 2020-12-12 00:00:00.000000000 Z
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: 1.3.1
118
+ version: '0'
118
119
  requirements: []
119
- rubygems_version: 3.1.4
120
+ rubygems_version: 3.2.22
120
121
  signing_key:
121
122
  specification_version: 4
122
123
  summary: Ruby bindings to libui