libui 0.3.0.pre2-x86_64-linux → 0.3.0.pre3-x86_64-linux

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: bea31e9c19a8fc1f2c1715cfe54a50462fe05c31f049703814e1a614ef10721c
4
- data.tar.gz: 40ab886b367dcbfdc5af0c4bfbba151cec7137abeadc37b7f91801d23ce55c2b
3
+ metadata.gz: cb3de132da0b423f122c492dd6735a75773863a3a79b98269ef0284e91bc795a
4
+ data.tar.gz: 965a16503f8df259c0832bd878815028ad8346627c1eaaedc0dd82bdf5efe2be
5
5
  SHA512:
6
- metadata.gz: df94026d4f8004d9c395190806f2df524100555496e48f8c026d2a2f0547d8aa6a5e2d63fe41dbcff8b06949f6f382e6fe0262adf5ddce59a8ebdf8a6ac02276
7
- data.tar.gz: ad66a39fb8f668c43466cba33bd745a75b038a32c038af0637e86880cc5288988ba10d695ffe16257d7725e000cd8a30c699c026304f5838aa410de0b82601e4
6
+ metadata.gz: 12dce58c3e8510568762e776d90e86b8ce4e9692462512406e687571063588e3201ce2f214f9a1a8440098e9a54910850bac321ddf962f424de2b33e32556262
7
+ data.tar.gz: 8f4b5b6cab26c42ae2ee1e9fce3848b633374eb986e2fa8516a178da8aae9d2e04e937f87cc8795357837abd1d8379e26d45b86c7513f5ae1c96f52aca8130e4
data/README.md CHANGED
@@ -1,287 +1,183 @@
1
1
  # LibUI
2
2
 
3
- [![test](https://github.com/kojix2/LibUI/actions/workflows/test.yml/badge.svg)](https://github.com/kojix2/LibUI/actions/workflows/test.yml)
4
- [![Gem Version](https://img.shields.io/badge/dynamic/json?label=gem%20version&query=%24%5B0%5D.number&url=https%3A%2F%2Frubygems.org%2Fapi%2Fv1%2Fversions%2Flibui.json&color=brightgreen)](https://rubygems.org/gems/libui/versions)
5
- [![Lines of Code](https://img.shields.io/endpoint?url=https%3A%2F%2Ftokei.kojix2.net%2Fbadge%2Fgithub%2Fkojix2%2FLibUI%2Flines)](https://tokei.kojix2.net/github/kojix2/LibUI)
6
- <a href="https://github.com/AndyObtiva/glimmer-dsl-libui"><img alt="glimmer-dsl-libui" src="https://github.com/AndyObtiva/glimmer/blob/master/images/glimmer-logo-hi-res.svg" width="50" height="50" align="right"></a>
3
+ [![Tests](https://github.com/kojix2/LibUI/actions/workflows/test.yml/badge.svg)](https://github.com/kojix2/LibUI/actions/workflows/test.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/libui)](https://rubygems.org/gems/libui)
7
5
 
8
- LibUI is a Ruby wrapper for libui family.
6
+ LibUI is a procedural Ruby binding for [libui-ng](https://github.com/libui-ng/libui-ng),
7
+ a native GUI library for Windows, macOS, and Linux. It uses
8
+ [Fiddle](https://github.com/ruby/fiddle) and keeps the C API's names and
9
+ structure, with Ruby-friendly values where they help.
9
10
 
10
- :rocket: [libui-ng](https://github.com/kojix2/libui-ng) - A cross-platform portable GUI library
11
+ ## Release lines
11
12
 
12
- ## Installation
13
+ This README describes the `main` branch and the 0.3.x series, which track the
14
+ newer libui-ng dev API. The 0.2.x series is maintained separately on
15
+ [`0.2-stable`](https://github.com/kojix2/LibUI/tree/0.2-stable) for compatibility
16
+ with the older libui-ng pre-build API. Existing 0.2.x applications can stay on
17
+ that series while it receives fixes and compatible additions.
13
18
 
14
- ```sh
15
- gem install libui # --pre
16
- ```
19
+ ## Screenshots
17
20
 
18
- - The gem package includes the libui-ng shared library for Windows, Mac, and Linux.
19
- - Namely `libui.x64.dll`/`libui.x86.dll`, `libui.x86_64.dylib`/`libui.arm64.dylib`, or `libui.x86_64.so`/`libui.aarch64.so`.
20
- - No dependencies required.
21
- - The libui gem uses the standard Ruby library [Fiddle](https://github.com/ruby/fiddle) to call C functions.
21
+ | Windows | macOS | Linux |
22
+ | --- | --- | --- |
23
+ | <img alt="LibUI window on Windows" src="https://user-images.githubusercontent.com/5798442/103118046-900ea780-46b0-11eb-81fc-32626762e4df.png"> | <img alt="LibUI window on macOS" src="https://user-images.githubusercontent.com/5798442/103118059-99980f80-46b0-11eb-9d12-324ec4d297c9.png"> | <img alt="LibUI window on Linux" src="https://user-images.githubusercontent.com/5798442/103118068-a0bf1d80-46b0-11eb-8c5c-3bdcc3dcfb26.png"> |
22
24
 
23
- | Windows | Mac | Linux |
24
- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
25
- | <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"> |
25
+ ## Install
26
26
 
27
- Notes:
27
+ ```sh
28
+ gem install libui
29
+ ```
28
30
 
29
- - If you are using the 32-bit (x86) version of Ruby, you need to download the 32-bit (x86) native dll. See the [Development](#development) section.
30
- - On Windows, libui may not work due to missing DLLs. In that case, you need to install [Visual C++ Redistributable](https://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist). See ([#48](https://github.com/kojix2/LibUI/issues/48))
31
- - Users with [Raspberry Pi](https://www.raspberrypi.com/) or other platforms will need to compile the C libui library. See the [Development](#development) section.
31
+ To install a prerelease version, use `gem install libui --pre`. Gems for
32
+ supported platforms include the libui-ng shared library. For a local libui-ng
33
+ build, set `LIBUIDIR` to the directory containing its `.dll`, `.dylib`, or
34
+ `.so` file. On Windows, the library may also need the
35
+ [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist).
32
36
 
33
- ## Usage
37
+ ## Quick start
34
38
 
35
39
  ```ruby
36
40
  require 'libui'
37
41
 
38
42
  UI = LibUI
39
-
40
43
  UI.init
41
44
 
42
- main_window = UI.new_window('hello world', 200, 100, 1)
43
-
44
- button = UI.new_button('Button')
45
-
45
+ window = UI.new_window('Hello', 300, 100, 0)
46
+ button = UI.new_button('Click me')
46
47
  UI.button_on_clicked(button) do
47
- UI.msg_box(main_window, 'Information', 'You clicked the button')
48
+ UI.msg_box(window, 'Hello', 'Button clicked')
48
49
  end
49
-
50
- UI.window_on_closing(main_window) do
51
- puts 'Bye Bye'
50
+ UI.window_set_child(window, button)
51
+ UI.window_on_closing(window) do
52
52
  UI.quit
53
53
  1
54
54
  end
55
55
 
56
- UI.window_set_child(main_window, button)
57
- UI.control_show(main_window)
58
-
56
+ UI.control_show(window)
59
57
  UI.main
60
- UI.quit
58
+ UI.uninit
61
59
  ```
62
60
 
63
- For more examples, see the [examples](https://github.com/kojix2/libui/tree/main/examples) directory.
61
+ Run the example with `ruby hello.rb`. Explore [examples](examples) for
62
+ individual controls and [examples2](examples2) for larger applications.
64
63
 
65
- ### General Rules
64
+ ## API
66
65
 
67
- Compared to the original libui library written in C:
66
+ Names follow libui-ng with `ui` removed and CamelCase converted to
67
+ `snake_case`: `uiNewWindow` becomes `LibUI.new_window`. Event callbacks accept
68
+ a block or `Proc`; LibUI retains them for the native owner's lifetime. The
69
+ [libui-ng API reference](https://libui-ng.github.io/libui-ng/) documents the
70
+ underlying controls and functions. `LibUI::FFI` exposes the original C bindings
71
+ when needed.
68
72
 
69
- - Method names use snake_case.
70
- - The last argument can be omitted if it's nil.
71
- - A block can be passed as a callback.
72
- - The block will be converted to a Proc object and added as the last argument.
73
- - The last argument can still be omitted when nil.
73
+ ### Ruby values
74
74
 
75
- You can use [the libui-ng API documentation](https://libui-ng.github.io/libui-ng/) as a reference.
75
+ Native controls, images, attributes, and text layouts are still represented by
76
+ Fiddle pointers. Common getters and setters use Ruby values:
76
77
 
77
- ### DSLs for LibUI
78
+ - Text and file dialog results are strings; a canceled file dialog returns `nil`.
79
+ - Size, position, color, and table selection results are arrays.
80
+ - Date and time picker methods use Ruby `Time`, `DateTime`, or `Date` values.
81
+ - Font getters return `LibUI::Font` values.
78
82
 
79
- LibUI is not object-oriented because it is a thin Ruby wrapper (binding) for the procedural C libui library, mirroring its API structure.
80
-
81
- To build actual applications, it is recommended to use a DSL for LibUI, as they enable writing object-oriented code the Ruby way (instead of procedural code the C way):
82
-
83
- - [Glimmer DSL for LibUI](https://github.com/AndyObtiva/glimmer-dsl-libui)
84
-
85
- ### Working with fiddle pointers
83
+ For example, inside a running UI session:
86
84
 
87
85
  ```ruby
88
- require 'libui'
89
- UI = LibUI
90
- UI.init
91
- ```
86
+ width, height = UI.window_content_size(window)
87
+ rows = UI.table_get_selection(table)
88
+ UI.table_set_selection(table, [1, 3])
89
+ UI.table_set_selection(table, []) # Clear the selection
92
90
 
93
- Text getter methods such as `label_text`, `entry_text`, and `window_title`
94
- return `Fiddle::Pointer` objects for strings allocated by libui. Convert the
95
- pointer to a Ruby string, then release it with `free_text`.
96
-
97
- ```ruby
98
- label = UI.new_label("Ruby")
99
- pointer = UI.label_text(label) # #<Fiddle::Pointer>
100
- text = pointer.to_s
101
- UI.free_text(pointer)
102
- p text # Ruby
91
+ path = UI.open_file(window) # A String, or nil if canceled
92
+ UI.date_time_picker_set_time(picker, Time.now)
93
+ selected_time = UI.date_time_picker_time(picker)
103
94
  ```
104
95
 
105
- Use `ensure` if the code between conversion and cleanup can raise:
96
+ Selection indices must exist in the table model; the selection mode controls
97
+ how many rows may be selected. `LibUI.version` returns the loaded libui-ng build
98
+ identifier as a string; `LibUI::VERSION` is the gem version.
106
99
 
107
- ```ruby
108
- def ui_text(text_pointer)
109
- text_pointer.to_s
110
- ensure
111
- UI.free_text(text_pointer) if text_pointer && !text_pointer.null?
112
- end
113
- ```
100
+ ### Drawing and tables
114
101
 
115
- If you need to use C structs, you can do the following:
102
+ The Ruby value classes `Font`, `Brush`, `StrokeParams`, and `Matrix` hide native
103
+ structs. `AreaHandler` and `TableModel` manage their callbacks. A drawing area
104
+ can use Ruby objects instead of manually allocating native structs:
116
105
 
117
106
  ```ruby
118
- font_button = UI.new_font_button
119
-
120
- # Allocate memory
121
- font_descriptor = UI::FFI::FontDescriptor.malloc
122
- font_descriptor.to_ptr.free = Fiddle::RUBY_FREE
123
- # font_descriptor = UI::FFI::FontDescriptor.malloc(Fiddle::RUBY_FREE) # fiddle 1.0.1 or higher
124
-
125
- UI.font_button_on_changed(font_button) do
126
- UI.font_button_font(font_button, font_descriptor)
127
- begin
128
- p family: font_descriptor.Family.to_s,
129
- size: font_descriptor.Size,
130
- weight: font_descriptor.Weight,
131
- italic: font_descriptor.Italic,
132
- stretch: font_descriptor.Stretch
133
- ensure
134
- UI.free_font_button_font(font_descriptor)
107
+ brush = UI::Brush.new(color: [0.4, 0.4, 0.8, 1.0])
108
+ handler = UI::AreaHandler.new(draw: ->(event) do
109
+ UI::Path.open do |path|
110
+ path.add_rectangle(0, 0, event.area_width, event.area_height).end_path
111
+ event.context.fill(path, brush)
135
112
  end
136
- end
113
+ end)
114
+ area = UI.new_area(handler)
137
115
  ```
138
116
 
139
- - Callbacks
140
- - In Ruby/Fiddle, a C callback function is written as an object of
141
- `Fiddle::Closure::BlockCaller` or `Fiddle::Closure`.
142
- Be careful about Ruby's garbage collection - if the function object is collected, memory will be freed resulting in a segmentation violation when the callback is invoked.
117
+ `Path.open` frees the drawing path when the block exits. For a table, provide
118
+ Ruby rows and their libui-ng column types:
143
119
 
144
120
  ```ruby
145
- # Assign to a local variable to prevent it from being collected by GC.
146
- handler.MouseEvent = (c1 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
147
- handler.MouseCrossed = (c2 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
148
- handler.DragBroken = (c3 = Fiddle::Closure::BlockCaller.new(0, [0]) {})
121
+ rows = [%w[cat meow], %w[dog woof]]
122
+ model = UI::TableModel.new(column_types: [UI::TableValueTypeString] * 2,
123
+ rows: rows)
124
+ table = UI.new_table(model: model)
125
+ UI.table_append_text_column(table, 'Animal', 0, -1)
126
+ UI.table_append_text_column(table, 'Sound', 1, -1)
127
+ # After destroying the table: model.free
149
128
  ```
150
129
 
151
- ### Creating a Windows executable (.exe) with OCRA
152
-
153
- OCRA (One-Click Ruby Application) builds Windows executables from Ruby source code.
130
+ See [basic_area.rb](examples/basic_area.rb),
131
+ [basic_draw_text.rb](examples/basic_draw_text.rb), and
132
+ [basic_table.rb](examples/basic_table.rb) for complete programs.
154
133
 
155
- - https://github.com/larsch/ocra/
134
+ ### Images
156
135
 
157
- To build an exe with Ocra, include 3 DLLs from the ruby_builtin_dlls folder:
136
+ Apart from library configuration, **`image_append_rgba` is the only procedural
137
+ helper without a direct C counterpart**. The C API's `uiImageAppend` requires
138
+ premultiplied RGBA bytes; `LibUI.image_append` has the same requirement.
139
+ `image_append_rgba(image, bytes, width, height)` accepts ordinary RGBA bytes,
140
+ converts a copy, and calls `image_append`:
158
141
 
159
- ```sh
160
- ocra examples/control_gallery.rb ^
161
- --dll ruby_builtin_dlls/libssp-0.dll ^
162
- --dll ruby_builtin_dlls/libgmp-10.dll ^
163
- --dll ruby_builtin_dlls/libffi-7.dll ^
164
- --gem-all=fiddle ^
142
+ ```ruby
143
+ image = UI.new_image(width, height)
144
+ UI.image_append_rgba(image, rgba_bytes, width, height)
165
145
  ```
166
146
 
167
- Add additional options below if necessary:
147
+ See [basic_table_image.rb](examples/basic_table_image.rb) for an example using
148
+ PNG data in a table.
168
149
 
169
- ```sh
170
- --window ^
171
- --add-all-core ^
172
- --chdir-first ^
173
- --icon assets\app.ico ^
174
- --verbose ^
175
- --output out\gallery.exe
176
- ```
150
+ ## Ownership
151
+
152
+ Native controls follow libui-ng's parent-child ownership rules. Destroy a
153
+ top-level control with `control_destroy`; destroying a parent also destroys its
154
+ children. Standalone resources such as images and text layouts have matching
155
+ `free_*` methods. Free a `TableModel` after the table using it has been
156
+ destroyed. `Path.open` handles path cleanup.
177
157
 
178
158
  ## Development
179
159
 
180
160
  ```sh
181
- git clone https://github.com/kojix2/libui
182
- cd libui
161
+ git clone https://github.com/kojix2/LibUI.git
162
+ cd LibUI
183
163
  bundle install
184
164
  bundle exec rake vendor:auto
185
165
  bundle exec rake test
186
166
  ```
187
167
 
188
- JRuby on macOS needs Java and AppKit must start on the first thread:
189
-
190
- ```sh
191
- export JAVA_HOME=/path/to/openjdk
192
- export JRUBY_OPTS=-J-XstartOnFirstThread
193
- jruby -Ilib examples/basic_button.rb
194
- jruby -S rake test
195
- ```
196
-
197
- Take note that, as the above code shows, LibUI works via jruby as well, so you have an additional
198
- GUI library (aside from jruby-swing by default) to test simple User Interfaces too.
199
-
200
- ### Pre-built shared libraries for libui-ng
201
-
202
- Download pre-built libui-ng shared libraries (per your current platform):
203
-
204
- ```sh
205
- bundle exec rake vendor:auto
206
- ```
207
-
208
- Clean downloaded vendor files (keeps `vendor/{LICENSE,README}.md`):
209
-
210
- ```sh
211
- bundle exec rake vendor:clean
212
- ```
213
-
214
- ### Using your own libui build
215
-
216
- If you build libui-ng yourself, set `LIBUIDIR` to the directory containing the compiled `.so/.dylib/.dll` so LibUI can load it. You may also replace files under `vendor/` with your build if preferred. See [#46](https://github.com/kojix2/LibUI/issues/46#issuecomment-1041575792).
217
-
218
- ### Publishing gems
219
-
220
- #### Automated Publishing
221
-
222
- Push a version tag to automatically publish platform-specific gems:
223
-
224
- ```sh
225
- git tag v0.2.0
226
- git push origin v0.2.0
227
- ```
228
-
229
- Requires `RUBYGEMS_API_KEY` repository secret with scoped API key.
230
-
231
- #### Manual Publishing
232
-
233
- ```sh
234
- ls vendor # check the vendor directory
235
- rm -rf pkg # remove previously built gems
236
- rake build_platform # build gems
237
-
238
- # Check the contents of the gem
239
- find pkg -name *.gem -exec sh -c "echo; echo \# {}; tar -O -f {} -x data.tar.gz | tar zt" \;
240
-
241
- rake release_platform # publish gems
242
- ```
243
-
244
- Windows Ruby (x64-mingw32 or x64-mingw-ucrt)
245
-
246
- ```sh
247
- gem install rake rubyzip
248
- GEM_PLATFORM=x64-mingw32 rake vendor:clean
249
- GEM_PLATFORM=x64-mingw32 rake vendor:auto
250
- GEM_PLATFORM=x64-mingw32 gem build libui.gemspec
251
- gem push libui-0.2.0-x64-mingw32.gem
252
- ```
253
-
254
- ### libui or libui-ng
255
-
256
- - From version 0.1.X, LibUI supports only libui-ng.
257
- - Version 0.0.X only supports andlabs/libui.
258
-
259
- ## Contributing
260
-
261
- Would you like to contribute to LibUI?
262
-
263
- - Please feel free to send us your [pull requests](https://github.com/kojix2/libui/pulls).
264
- - Small corrections, such as typo fixes, are appreciated.
265
- - Did you find any bugs? Submit them in the [issues](https://github.com/kojix2/LibUI/issues) section!
266
-
267
- Do you need commit rights?
268
-
269
- - If you need commit rights to my repository or want to get admin rights and take over the project, please feel free to contact @kojix2.
270
- - Many OSS projects become abandoned because only the founder has commit rights to the original repository.
271
-
272
- Support libui-ng development
273
-
274
- - Contributing to the development of libui-ng is a contribution to the entire libui community, including Ruby's LibUI.
275
- - For example, it would be easier to release LibUI in Ruby if libui-ng could be built easily and official shared libraries could be distributed.
276
-
277
- ## Acknowledgements
278
-
279
- This project is inspired by libui-ruby.
168
+ The tests need a GUI display. On macOS with JRuby, set
169
+ `JRUBY_OPTS=-J-XstartOnFirstThread`. `bundle exec rake vendor:clean` removes
170
+ downloaded binaries. The [RubyGems release workflow](.github/workflows/release-rubygems.yml)
171
+ builds and publishes gems from version tags using trusted publishing.
280
172
 
281
- - https://github.com/jamescook/libui-ruby
173
+ ## Related projects and contributing
282
174
 
283
- While libui-ruby uses [Ruby-FFI](https://github.com/ffi/ffi), this gem uses [Fiddle](https://github.com/ruby/fiddle).
175
+ For an object-oriented DSL built on LibUI, see
176
+ [Glimmer DSL for LibUI](https://github.com/AndyObtiva/glimmer-dsl-libui).
177
+ LibUI was inspired by [libui-ruby](https://github.com/jamescook/libui-ruby).
178
+ Bug reports and pull requests are welcome in the
179
+ [GitHub repository](https://github.com/kojix2/LibUI).
284
180
 
285
181
  ## License
286
182
 
287
- [MIT License](https://opensource.org/licenses/MIT).
183
+ [MIT](LICENSE.txt)
@@ -0,0 +1,155 @@
1
+ module LibUI
2
+ class DrawContext
3
+ def initialize(pointer)
4
+ @pointer = Fiddle::Pointer.new(pointer.to_i)
5
+ @active = true
6
+ end
7
+
8
+ def to_ptr
9
+ raise RuntimeError, 'draw context is only valid during on_draw' unless @active
10
+
11
+ @pointer
12
+ end
13
+
14
+ def fill(path, brush)
15
+ LibUI.draw_fill(to_ptr, path, brush)
16
+ end
17
+
18
+ def stroke(path, brush, stroke_params)
19
+ LibUI.draw_stroke(to_ptr, path, brush, stroke_params)
20
+ end
21
+
22
+ def draw_text(layout, x, y)
23
+ LibUI.draw_text(to_ptr, layout, x, y)
24
+ end
25
+
26
+ def draw_image(image, x, y, width, height)
27
+ LibUI.draw_image(to_ptr, image, x, y, width, height)
28
+ end
29
+
30
+ def transform(matrix)
31
+ LibUI.draw_transform(to_ptr, matrix)
32
+ end
33
+
34
+ def clip(path)
35
+ LibUI.draw_clip(to_ptr, path)
36
+ end
37
+
38
+ def save
39
+ LibUI.draw_save(to_ptr)
40
+ end
41
+
42
+ def restore
43
+ LibUI.draw_restore(to_ptr)
44
+ end
45
+
46
+ def invalidate
47
+ @active = false
48
+ end
49
+ end
50
+
51
+ class AreaHandler
52
+ DrawEvent = Struct.new(:context, :area_width, :area_height, :clip_x, :clip_y,
53
+ :clip_width, :clip_height, keyword_init: true)
54
+ MouseEvent = Struct.new(:x, :y, :area_width, :area_height, :down, :up,
55
+ :count, :modifiers, :held_1_to_64, keyword_init: true)
56
+ KeyEvent = Struct.new(:key, :ext_key, :modifier, :modifiers, :up,
57
+ keyword_init: true)
58
+
59
+ def initialize(draw: nil, mouse_event: nil, mouse_crossed: nil,
60
+ drag_broken: nil, key_event: nil)
61
+ @handlers = { draw: draw, mouse_event: mouse_event,
62
+ mouse_crossed: mouse_crossed, drag_broken: drag_broken,
63
+ key_event: key_event }
64
+ @native = FFI::AreaHandler.malloc
65
+ @native.to_ptr.free = Fiddle::RUBY_FREE
66
+ @closures = {}
67
+ install_callbacks
68
+ end
69
+
70
+ def to_ptr
71
+ @native.to_ptr
72
+ end
73
+
74
+ def on_draw(&block)
75
+ @handlers[:draw] = block
76
+ self
77
+ end
78
+
79
+ def on_mouse_event(&block)
80
+ @handlers[:mouse_event] = block
81
+ self
82
+ end
83
+
84
+ def on_mouse_crossed(&block)
85
+ @handlers[:mouse_crossed] = block
86
+ self
87
+ end
88
+
89
+ def on_drag_broken(&block)
90
+ @handlers[:drag_broken] = block
91
+ self
92
+ end
93
+
94
+ def on_key_event(&block)
95
+ @handlers[:key_event] = block
96
+ self
97
+ end
98
+
99
+ private
100
+
101
+ def install_callbacks
102
+ pointer = Fiddle::TYPE_VOIDP
103
+ integer = Fiddle::TYPE_INT
104
+ @closures[:draw] = callback(Fiddle::TYPE_VOID, [pointer, pointer, pointer]) do |_handler, _area, params_ptr|
105
+ params = FFI::AreaDrawParams.new(params_ptr)
106
+ context = DrawContext.new(params.Context)
107
+ event = DrawEvent.new(context: context, area_width: params.AreaWidth,
108
+ area_height: params.AreaHeight, clip_x: params.ClipX,
109
+ clip_y: params.ClipY, clip_width: params.ClipWidth,
110
+ clip_height: params.ClipHeight)
111
+ begin
112
+ @handlers[:draw]&.call(event)
113
+ ensure
114
+ context.invalidate
115
+ end
116
+ end
117
+ @closures[:mouse_event] = callback(Fiddle::TYPE_VOID, [pointer, pointer, pointer]) do |_handler, _area, event_ptr|
118
+ native = FFI::AreaMouseEvent.new(event_ptr)
119
+ @handlers[:mouse_event]&.call(MouseEvent.new(x: native.X, y: native.Y,
120
+ area_width: native.AreaWidth, area_height: native.AreaHeight,
121
+ down: native.Down, up: native.Up, count: native.Count,
122
+ modifiers: native.Modifiers, held_1_to_64: native.Held1To64))
123
+ end
124
+ @closures[:mouse_crossed] = callback(Fiddle::TYPE_VOID, [pointer, pointer, integer]) do |_handler, _area, left|
125
+ @handlers[:mouse_crossed]&.call(left != 0)
126
+ end
127
+ @closures[:drag_broken] = callback(Fiddle::TYPE_VOID, [pointer, pointer]) do |_handler, _area|
128
+ @handlers[:drag_broken]&.call
129
+ end
130
+ @closures[:key_event] = callback(integer, [pointer, pointer, pointer]) do |_handler, _area, event_ptr|
131
+ native = FFI::AreaKeyEvent.new(event_ptr)
132
+ event = KeyEvent.new(key: native.Key, ext_key: native.ExtKey,
133
+ modifier: native.Modifier, modifiers: native.Modifiers,
134
+ up: native.Up != 0)
135
+ @handlers[:key_event]&.call(event) ? 1 : 0
136
+ end
137
+ @native.Draw = @closures[:draw]
138
+ @native.MouseEvent = @closures[:mouse_event]
139
+ @native.MouseCrossed = @closures[:mouse_crossed]
140
+ @native.DragBroken = @closures[:drag_broken]
141
+ @native.KeyEvent = @closures[:key_event]
142
+ end
143
+
144
+ def callback(return_type, argument_types, &block)
145
+ Fiddle::Closure::BlockCaller.new(return_type, argument_types) do |*args|
146
+ begin
147
+ block.call(*args)
148
+ rescue StandardError => e
149
+ CallbackRegistry.report(e)
150
+ 0
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end