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 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