libui 0.2.4-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 +4 -4
- data/README.md +114 -218
- data/lib/libui/area_handler.rb +155 -0
- data/lib/libui/callback_registry.rb +123 -0
- data/lib/libui/draw_values.rb +143 -0
- data/lib/libui/ffi.rb +45 -1
- data/lib/libui/font.rb +13 -0
- data/lib/libui/libui_base.rb +23 -29
- data/lib/libui/path.rb +70 -0
- data/lib/libui/platform.rb +12 -12
- data/lib/libui/table_model.rb +175 -0
- data/lib/libui/version.rb +1 -1
- data/lib/libui.rb +605 -2
- data/vendor/libui.x86_64.so +0 -0
- metadata +8 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cb3de132da0b423f122c492dd6735a75773863a3a79b98269ef0284e91bc795a
|
|
4
|
+
data.tar.gz: 965a16503f8df259c0832bd878815028ad8346627c1eaaedc0dd82bdf5efe2be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 12dce58c3e8510568762e776d90e86b8ce4e9692462512406e687571063588e3201ce2f214f9a1a8440098e9a54910850bac321ddf962f424de2b33e32556262
|
|
7
|
+
data.tar.gz: 8f4b5b6cab26c42ae2ee1e9fce3848b633374eb986e2fa8516a178da8aae9d2e04e937f87cc8795357837abd1d8379e26d45b86c7513f5ae1c96f52aca8130e4
|
data/README.md
CHANGED
|
@@ -1,287 +1,183 @@
|
|
|
1
1
|
# LibUI
|
|
2
2
|
|
|
3
|
-
[](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
|
+
[](https://github.com/kojix2/LibUI/actions/workflows/test.yml)
|
|
4
|
+
[](https://rubygems.org/gems/libui)
|
|
7
5
|
|
|
8
|
-
LibUI is a Ruby
|
|
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
|
-
|
|
11
|
+
## Release lines
|
|
11
12
|
|
|
12
|
-
|
|
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
|
-
|
|
15
|
-
gem install libui # --pre
|
|
16
|
-
```
|
|
19
|
+
## Screenshots
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
27
|
+
```sh
|
|
28
|
+
gem install libui
|
|
29
|
+
```
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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(
|
|
48
|
+
UI.msg_box(window, 'Hello', 'Button clicked')
|
|
48
49
|
end
|
|
49
|
-
|
|
50
|
-
UI.window_on_closing(
|
|
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.
|
|
57
|
-
UI.control_show(main_window)
|
|
58
|
-
|
|
56
|
+
UI.control_show(window)
|
|
59
57
|
UI.main
|
|
60
|
-
UI.
|
|
58
|
+
UI.uninit
|
|
61
59
|
```
|
|
62
60
|
|
|
63
|
-
|
|
61
|
+
Run the example with `ruby hello.rb`. Explore [examples](examples) for
|
|
62
|
+
individual controls and [examples2](examples2) for larger applications.
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
## API
|
|
66
65
|
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
UI.
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
140
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
134
|
+
### Images
|
|
156
135
|
|
|
157
|
-
|
|
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
|
-
```
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
147
|
+
See [basic_table_image.rb](examples/basic_table_image.rb) for an example using
|
|
148
|
+
PNG data in a table.
|
|
168
149
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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/
|
|
182
|
-
cd
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
173
|
+
## Related projects and contributing
|
|
282
174
|
|
|
283
|
-
|
|
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
|
|
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
|