glimmer-dsl-libui 0.0.26 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +417 -7
- data/VERSION +1 -1
- data/examples/basic_area.rb +17 -0
- data/examples/basic_area2.rb +19 -0
- data/examples/basic_table_checkbox_text.rb +1 -3
- data/examples/dynamic_area.rb +99 -0
- data/examples/form_table.rb +67 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/fiddle_consumer.rb +33 -0
- data/lib/glimmer/libui/area_proxy.rb +105 -0
- data/lib/glimmer/libui/button_column_proxy.rb +6 -1
- data/lib/glimmer/libui/checkbox_column_proxy.rb +2 -2
- data/lib/glimmer/libui/checkbox_text_column_proxy.rb +34 -2
- data/lib/glimmer/libui/path_proxy.rb +149 -0
- data/lib/glimmer/libui/rectangle_proxy.rb +56 -0
- data/lib/glimmer/libui/table_proxy.rb +18 -17
- data/lib/glimmer/libui/window_proxy.rb +7 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0938fd7cd0d762ecf27c7897a6305ec9a1d8b447917c4612c864e87486e44241'
|
4
|
+
data.tar.gz: 7387d2a5d966bbf5f2e70184013cc8056023b94375b1ec1e9941bcdac0c8da27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c44c83599999686358def664edf39c9f4cdcac415fd608d3668109eaba098b296cd27ce33130d8b0318904f89b406a5bddc2df808233f85c5474dc1165bbbfd2
|
7
|
+
data.tar.gz: c9d69205562886250e16359b5db53d426d4cea2d96da8bdac34c41b1488f7cd74e9e3864fa82636cd351169fab60e945f56a19f5219fc59312b4fc5d11e63770
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.1.1
|
4
|
+
|
5
|
+
- Support `area` listener: `on_draw`
|
6
|
+
- New examples/basic_area2.rb
|
7
|
+
|
8
|
+
## 0.1.0
|
9
|
+
|
10
|
+
- Support examples/basic_area.rb
|
11
|
+
- Support `area` control
|
12
|
+
- Support `path(fill_mode)` control
|
13
|
+
- Support `rectangle(x, y, width, height)` figure
|
14
|
+
- Support `path` `fill` property
|
15
|
+
- Support `path` `stroke` property
|
16
|
+
|
17
|
+
## 0.0.28
|
18
|
+
|
19
|
+
- Support automatic table row change when updating a row in `cell_rows` (e.g. `data[3] = ['new', 'row', 'cell', 'values']`)
|
20
|
+
- Support `editable` property for `checkbox_column` (checkbox editing only works in Windows due to a [libui](https://github.com/andlabs/libui) limitation)
|
21
|
+
- Support `editable`, `editable_checkbox`, and `editable_text` properties for `checkbox_text_column` (checkbox editing only works in Windows due to a [libui](https://github.com/andlabs/libui) limitation)
|
22
|
+
- Fix examples/basic_table_checkbox_text.rb by removing `editable` property
|
23
|
+
|
24
|
+
## 0.0.27
|
25
|
+
|
26
|
+
- New examples/form_table.rb
|
27
|
+
- Support automatic table row insertion upon inserting data rows into `cell_rows`
|
28
|
+
|
3
29
|
## 0.0.26
|
4
30
|
|
5
31
|
- New examples/basic_table_progress_bar.rb
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.
|
1
|
+
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for LibUI 0.1.1
|
2
2
|
## Prerequisite-Free Ruby Desktop Development GUI Library
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
|
4
4
|
[![Maintainability](https://api.codeclimate.com/v1/badges/ce2853efdbecf6ebdc73/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-libui/maintainability)
|
@@ -43,7 +43,7 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
43
43
|
|
44
44
|
## Table of Contents
|
45
45
|
|
46
|
-
- [Glimmer DSL for LibUI 0.
|
46
|
+
- [Glimmer DSL for LibUI 0.1.1](#-glimmer-dsl-for-libui-011)
|
47
47
|
- [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts)
|
48
48
|
- [Usage](#usage)
|
49
49
|
- [API](#api)
|
@@ -52,6 +52,8 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
52
52
|
- [Common Control Operations](#common-control-operations)
|
53
53
|
- [Extra Dialogs](#extra-dialogs)
|
54
54
|
- [Extra Operations](#extra-operations)
|
55
|
+
- [Table API](#table-api)
|
56
|
+
- [Area API](#area-api)
|
55
57
|
- [Smart Defaults and Conventions](#smart-defaults-and-conventions)
|
56
58
|
- [API Gotchas](#api-gotchas)
|
57
59
|
- [Original API](#original-api)
|
@@ -78,6 +80,9 @@ Other [Glimmer](https://rubygems.org/gems/glimmer) DSL gems you might be interes
|
|
78
80
|
- [Basic Table Checkbox](#basic-table-checkbox)
|
79
81
|
- [Basic Table Checkbox Text](#basic-table-checkbox-text)
|
80
82
|
- [Basic Table Progress Bar](#basic-table-progress-bar)
|
83
|
+
- [Form Table](#form-table)
|
84
|
+
- [Basic Area](#basic-area)
|
85
|
+
- [Dynamic Area](#dynamic-area)
|
81
86
|
- [Contributing to glimmer-dsl-libui](#contributing-to-glimmer-dsl-libui)
|
82
87
|
- [Help](#help)
|
83
88
|
- [Issues](#issues)
|
@@ -165,7 +170,7 @@ gem install glimmer-dsl-libui
|
|
165
170
|
Or install via Bundler `Gemfile`:
|
166
171
|
|
167
172
|
```ruby
|
168
|
-
gem 'glimmer-dsl-libui', '~> 0.
|
173
|
+
gem 'glimmer-dsl-libui', '~> 0.1.1'
|
169
174
|
```
|
170
175
|
|
171
176
|
Add `require 'glimmer-dsl-libui'` at the top, and then `include Glimmer` into the top-level main object for testing or into an actual class for serious usage.
|
@@ -221,11 +226,12 @@ w.libui # => #<Fiddle::Pointer:0x00007fde53997980 ptr=0x00007fde51352a60 size=0
|
|
221
226
|
Control(Args) | Properties | Listeners
|
222
227
|
------------- | ---------- | ---------
|
223
228
|
`about_menu_item` | None | `on_clicked`
|
229
|
+
`area` | None | `on_draw`
|
224
230
|
`button(text as String)` | `text` (`String`) | `on_clicked`
|
225
231
|
`button_column(name as String)` | `enabled` (Boolean) | None
|
226
232
|
`checkbox(text as String)` | `checked` (Boolean), `text` (`String`) | `on_toggled`
|
227
|
-
`checkbox_column(name as String)` |
|
228
|
-
`checkbox_text_column(name as String)` | `editable` (Boolean) | None
|
233
|
+
`checkbox_column(name as String)` | `editable` (Boolean) | None
|
234
|
+
`checkbox_text_column(name as String)` | `editable` (Boolean), `editable_checkbox` (Boolean), `editable_text` (Boolean) | None
|
229
235
|
`combobox` | `items` (`Array` of `String`), `selected` (`Integer`) | `on_selected`
|
230
236
|
`color_button` | `color` (Array of `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float`), `red` as `Float`, `green` as `Float`, `blue` as `Float`, `alpha` as `Float` | `on_changed`
|
231
237
|
`date_picker` | `time` (`Hash` of keys: `sec` as `Integer`, `min` as `Integer`, `hour` as `Integer`, `mday` as `Integer`, `mon` as `Integer`, `year` as `Integer`, `wday` as `Integer`, `yday` as `Integer`, `dst` as Boolean) | `on_changed`
|
@@ -249,11 +255,13 @@ Control(Args) | Properties | Listeners
|
|
249
255
|
`msg_box(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
|
250
256
|
`msg_box_error(window as Glimmer::LibUI::WindowProxy, title as String, description as String)` | None | None
|
251
257
|
`non_wrapping_multiline_entry` | `read_only` (Boolean), `text` (`String`) | `on_changed`
|
258
|
+
`path` | `fill` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`), `stroke` (`Hash` of `:r` as `0`-`255`, `:g` as `0`-`255`, `:b` as `0`-`255`, `:a` as `0.0`-`1.0`, `:cap` as `Numeric`, `:join` as `Numeric`, `:thickness` as `Numeric`, `:miter_limit` as `Numeric` ) | None
|
252
259
|
`preferences_menu_item` | None | `on_clicked`
|
253
260
|
`progress_bar` | `value` (`Numeric`) | None
|
254
261
|
`progress_bar_column(name as String)` | None | None
|
255
262
|
`quit_menu_item` | None | `on_clicked`
|
256
263
|
`radio_buttons` | `selected` (`Integer`) | `on_selected`
|
264
|
+
`rectangle(x as Numeric, y as Numeric, width as Numeric, height as Numeric)` | None | None
|
257
265
|
`slider(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
258
266
|
`spinbox(min as Numeric, max as Numeric)` | `value` (`Numeric`) | `on_changed`
|
259
267
|
`tab` | `margined` (Boolean), `num_pages` (`Integer`) | None
|
@@ -301,6 +309,82 @@ Control(Args) | Properties | Listeners
|
|
301
309
|
- `ControlProxy::main_window_proxy`: returns the first window proxy instantiated in the application
|
302
310
|
- `ControlProxy#window_proxy`: returns the window proxy parent for a control
|
303
311
|
|
312
|
+
### Table API
|
313
|
+
|
314
|
+
The `table` control must first declare its columns via one of these column keywords (mentioned in [Supported Controls](#supported-controls)):
|
315
|
+
- `button_column`: expects `String` cell values
|
316
|
+
- `checkbox_column`: expects Boolean cell values
|
317
|
+
- `checkbox_text_column`: expects dual-element `Array` of Boolean and `String` cell values
|
318
|
+
- `image_column`: expects `image` cell values (produced by `image` and `image_part` keywords as per [Supported Controls](#supported-controls))
|
319
|
+
- `image_text_column`: expects dual-element `Array` of `image` and `String` cell values
|
320
|
+
- `text_column`: expects `String` cell values
|
321
|
+
- `progress_bar_column`: expects `Integer` cell values
|
322
|
+
|
323
|
+
Afterwards, it must declare its `cell_rows` array (`Array` of `Array`s of column cell values) and whether it is `editable` (Boolean) for all its columns.
|
324
|
+
|
325
|
+
Note that the `cell_rows` property declaration results in "implicit data-binding" between the `table` control and `Array` of `Arrays` (a new innovation) to provide convenience automatic support for:
|
326
|
+
- Deleting cell rows: Calling `Array#delete`, `Array#delete_at`, `Array#delete_if`, or any filtering/deletion `Array` method automatically deletes rows in actual `table` control
|
327
|
+
- Inserting cell rows: Calling `Array#<<`, `Array#push`, `Array#prepend`, or any insertion/addition `Array` method automatically inserts rows in actual `table` control
|
328
|
+
- Changing cell rows: Calling `Array#[]=`, `Array#map!`, or any update `Array` method automatically updates rows in actual `table` control
|
329
|
+
|
330
|
+
### Area API
|
331
|
+
|
332
|
+
The `area` control can be used in one of two ways:
|
333
|
+
- Declaratively via stable paths: useful for stable paths that will not change later on. Simply nest `path` and figures like `rectangle` and all drawing logic is generated automatically.
|
334
|
+
- Semi-declaratively via on_draw listener dynamic paths: useful for more dynamic paths that will definitely change. Open an `on_draw` listener block and nest `path(area_draw_params)` and figures like `rectangle` and all drawing logic is generated automatically.
|
335
|
+
|
336
|
+
Here is an example of a declarative `area` with a stable path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
require 'glimmer-dsl-libui'
|
340
|
+
|
341
|
+
include Glimmer
|
342
|
+
|
343
|
+
window('Basic Area', 400, 400) {
|
344
|
+
margined true
|
345
|
+
|
346
|
+
vertical_box {
|
347
|
+
area {
|
348
|
+
path { # a stable path is added declaratively
|
349
|
+
rectangle(0, 0, 400, 400)
|
350
|
+
|
351
|
+
fill r: 102, g: 102, b: 204, a: 1.0
|
352
|
+
}
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}.show
|
356
|
+
```
|
357
|
+
|
358
|
+
![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png)
|
359
|
+
|
360
|
+
Here is the same example using a semi-declarative `area` with `on_draw` listener and a dynamic path (you may copy/paste in [`girb`](#girb-glimmer-irb)):
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
require 'glimmer-dsl-libui'
|
364
|
+
|
365
|
+
include Glimmer
|
366
|
+
|
367
|
+
window('Basic Area', 400, 400) {
|
368
|
+
margined true
|
369
|
+
|
370
|
+
vertical_box {
|
371
|
+
area {
|
372
|
+
on_draw do |area_draw_params|
|
373
|
+
path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
|
374
|
+
rectangle(0, 0, 400, 400)
|
375
|
+
|
376
|
+
fill r: 102, g: 102, b: 204, a: 1.0
|
377
|
+
}
|
378
|
+
end
|
379
|
+
}
|
380
|
+
}
|
381
|
+
}.show
|
382
|
+
```
|
383
|
+
|
384
|
+
Check [examples/dynamic_area.rb](#dynamic-area) for a more detailed semi-declarative example.
|
385
|
+
|
386
|
+
To redraw an `area`, you may call `#queue_redraw_all` method.
|
387
|
+
|
304
388
|
### Smart Defaults and Conventions
|
305
389
|
|
306
390
|
- `horizontal_box`, `vertical_box`, `grid`, and `form` controls have `padded` as `true` upon instantiation to ensure more user-friendly GUI by default
|
@@ -326,13 +410,15 @@ Control(Args) | Properties | Listeners
|
|
326
410
|
- Smart defaults for `grid` child attributes are `left` (`0`), `top` (`0`), `xspan` (`1`), `yspan` (`1`), `hexpand` (`false`), `halign` (`0`), `vexpand` (`false`), and `valign` (`0`)
|
327
411
|
- The `table` control automatically constructs required `TableModelHandler`, `TableModel`, and `TableParams`, calculating all their arguments from `cell_rows` and `editable` properties (e.g. `NumRows`) as well as nested columns (e.g. `text_column`)
|
328
412
|
- Table model instances are automatically freed from memory after `window` is destroyed.
|
329
|
-
- Table `cell_rows` data has implicit data-binding to table cell values. When deleting data from `cell_rows` array, then actual rows from the `table` are automatically deleted.
|
413
|
+
- Table `cell_rows` data has implicit data-binding to table cell values for deletion, insertion, and change (done by diffing `cell_rows` value before and after change and auto-informing `table` of deletions [`LibUI.table_model_row_deleted`], insertions [`LibUI.table_model_row_deleted`], and changes [`LibUI.table_model_row_changed`]). When deleting data rows from `cell_rows` array, then actual rows from the `table` are automatically deleted. When inserting data rows into `cell_rows` array, then actual `table` rows are automatically inserted. When updating data rows in `cell_rows` array, then actual `table` rows are automatically updated.
|
330
414
|
- `image` instances are automatically freed from memory after `window` is destroyed.
|
331
415
|
- `image` `width` and `height` can be left off if it has one `image_part` only as they default to the same `width` and `height` of the `image_part`
|
416
|
+
- `area` paths are specified declaratively with figures underneath (e.g. `rectangle`) and `area` draw listener is automatically generated
|
332
417
|
|
333
418
|
### API Gotchas
|
334
419
|
|
335
|
-
There is no proper way to destroy `grid` children due to [libui](https://github.com/andlabs/libui) not offering any API for deleting them from `grid` (no `grid_delete` similar to `box_delete` for `horizontal_box` and `vertical_box`)
|
420
|
+
- There is no proper way to destroy `grid` children due to [libui](https://github.com/andlabs/libui) not offering any API for deleting them from `grid` (no `grid_delete` similar to `box_delete` for `horizontal_box` and `vertical_box`).
|
421
|
+
- `table` `checkbox_column` and `checkbox_text_column` checkbox editing only works on Windows and Linux (not Mac) due to a current limitation in [libui](https://github.com/andlabs/ui/issues/357).
|
336
422
|
|
337
423
|
### Original API
|
338
424
|
|
@@ -2464,6 +2550,330 @@ window('Task progress', 300, 200) {
|
|
2464
2550
|
}.show
|
2465
2551
|
```
|
2466
2552
|
|
2553
|
+
### Form Table
|
2554
|
+
|
2555
|
+
[examples/form_table.rb](examples/form_table.rb)
|
2556
|
+
|
2557
|
+
Run with this command from the root of the project if you cloned the project:
|
2558
|
+
|
2559
|
+
```
|
2560
|
+
ruby -r './lib/glimmer-dsl-libui' examples/form_table.rb
|
2561
|
+
```
|
2562
|
+
|
2563
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
2564
|
+
|
2565
|
+
```
|
2566
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/form_table'"
|
2567
|
+
```
|
2568
|
+
|
2569
|
+
Mac
|
2570
|
+
|
2571
|
+
![glimmer-dsl-libui-mac-form-table.png](images/glimmer-dsl-libui-mac-form-table.png)
|
2572
|
+
![glimmer-dsl-libui-mac-form-table-contact-entered.png](images/glimmer-dsl-libui-mac-form-table-contact-entered.png)
|
2573
|
+
|
2574
|
+
Linux
|
2575
|
+
|
2576
|
+
![glimmer-dsl-libui-linux-form-table.png](images/glimmer-dsl-libui-linux-form-table.png)
|
2577
|
+
![glimmer-dsl-libui-linux-form-table-contact-entered.png](images/glimmer-dsl-libui-linux-form-table-contact-entered.png)
|
2578
|
+
|
2579
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2580
|
+
|
2581
|
+
```ruby
|
2582
|
+
require 'glimmer-dsl-libui'
|
2583
|
+
|
2584
|
+
include Glimmer
|
2585
|
+
|
2586
|
+
data = [
|
2587
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
|
2588
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
|
2589
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
|
2590
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
|
2591
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
|
2592
|
+
]
|
2593
|
+
|
2594
|
+
window('Contacts', 600, 600) { |w|
|
2595
|
+
margined true
|
2596
|
+
|
2597
|
+
vertical_box {
|
2598
|
+
form {
|
2599
|
+
stretchy false
|
2600
|
+
|
2601
|
+
@name_entry = entry {
|
2602
|
+
label 'Name'
|
2603
|
+
}
|
2604
|
+
@email_entry = entry {
|
2605
|
+
label 'Email'
|
2606
|
+
}
|
2607
|
+
@phone_entry = entry {
|
2608
|
+
label 'Phone'
|
2609
|
+
}
|
2610
|
+
@city_entry = entry {
|
2611
|
+
label 'City'
|
2612
|
+
}
|
2613
|
+
@state_entry = entry {
|
2614
|
+
label 'State'
|
2615
|
+
}
|
2616
|
+
}
|
2617
|
+
|
2618
|
+
button('Save Contact') {
|
2619
|
+
stretchy false
|
2620
|
+
|
2621
|
+
on_clicked do
|
2622
|
+
new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
|
2623
|
+
if new_row.include?('')
|
2624
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
2625
|
+
else
|
2626
|
+
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
2627
|
+
@name_entry.text = ''
|
2628
|
+
@email_entry.text = ''
|
2629
|
+
@phone_entry.text = ''
|
2630
|
+
@city_entry.text = ''
|
2631
|
+
@state_entry.text = ''
|
2632
|
+
end
|
2633
|
+
end
|
2634
|
+
}
|
2635
|
+
|
2636
|
+
table {
|
2637
|
+
text_column('Name')
|
2638
|
+
text_column('Email')
|
2639
|
+
text_column('Phone')
|
2640
|
+
text_column('City')
|
2641
|
+
text_column('State')
|
2642
|
+
|
2643
|
+
cell_rows data # implicit data-binding
|
2644
|
+
}
|
2645
|
+
}
|
2646
|
+
}.show
|
2647
|
+
```
|
2648
|
+
|
2649
|
+
### Basic Area
|
2650
|
+
|
2651
|
+
[examples/basic_area.rb](examples/basic_area.rb)
|
2652
|
+
|
2653
|
+
Run with this command from the root of the project if you cloned the project:
|
2654
|
+
|
2655
|
+
```
|
2656
|
+
ruby -r './lib/glimmer-dsl-libui' examples/basic_area.rb
|
2657
|
+
```
|
2658
|
+
|
2659
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
2660
|
+
|
2661
|
+
```
|
2662
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/basic_area'"
|
2663
|
+
```
|
2664
|
+
|
2665
|
+
Mac
|
2666
|
+
|
2667
|
+
![glimmer-dsl-libui-mac-basic-area.png](images/glimmer-dsl-libui-mac-basic-area.png)
|
2668
|
+
|
2669
|
+
Linux
|
2670
|
+
|
2671
|
+
![glimmer-dsl-libui-linux-basic-area.png](images/glimmer-dsl-libui-linux-basic-area.png)
|
2672
|
+
|
2673
|
+
[LibUI](https://github.com/kojix2/LibUI) Original Version:
|
2674
|
+
|
2675
|
+
```ruby
|
2676
|
+
require 'libui'
|
2677
|
+
|
2678
|
+
UI = LibUI
|
2679
|
+
|
2680
|
+
UI.init
|
2681
|
+
|
2682
|
+
handler = UI::FFI::AreaHandler.malloc
|
2683
|
+
area = UI.new_area(handler)
|
2684
|
+
brush = UI::FFI::DrawBrush.malloc
|
2685
|
+
|
2686
|
+
handler_draw_event = Fiddle::Closure::BlockCaller.new(0, [1, 1, 1]) do |_, _, area_draw_params|
|
2687
|
+
path = UI.draw_new_path(0)
|
2688
|
+
UI.draw_path_add_rectangle(path, 0, 0, 400, 400)
|
2689
|
+
UI.draw_path_end(path)
|
2690
|
+
brush.Type = 0
|
2691
|
+
brush.R = 0.4
|
2692
|
+
brush.G = 0.4
|
2693
|
+
brush.B = 0.8
|
2694
|
+
brush.A = 1.0
|
2695
|
+
area_draw_params = UI::FFI::AreaDrawParams.new(area_draw_params)
|
2696
|
+
UI.draw_fill(area_draw_params.Context, path, brush.to_ptr)
|
2697
|
+
UI.draw_free_path(path)
|
2698
|
+
end
|
2699
|
+
|
2700
|
+
handler.Draw = handler_draw_event
|
2701
|
+
handler.MouseEvent = Fiddle::Closure::BlockCaller.new(0, [0]) {}
|
2702
|
+
handler.MouseCrossed = Fiddle::Closure::BlockCaller.new(0, [0]) {}
|
2703
|
+
handler.DragBroken = Fiddle::Closure::BlockCaller.new(0, [0]) {}
|
2704
|
+
handler.KeyEvent = Fiddle::Closure::BlockCaller.new(0, [0]) {}
|
2705
|
+
|
2706
|
+
box = UI.new_vertical_box
|
2707
|
+
UI.box_set_padded(box, 1)
|
2708
|
+
UI.box_append(box, area, 1)
|
2709
|
+
|
2710
|
+
main_window = UI.new_window('Basic Area', 400, 400, 1)
|
2711
|
+
UI.window_set_margined(main_window, 1)
|
2712
|
+
UI.window_set_child(main_window, box)
|
2713
|
+
|
2714
|
+
UI.window_on_closing(main_window) do
|
2715
|
+
UI.control_destroy(main_window)
|
2716
|
+
UI.quit
|
2717
|
+
0
|
2718
|
+
end
|
2719
|
+
UI.control_show(main_window)
|
2720
|
+
|
2721
|
+
UI.main
|
2722
|
+
UI.quit
|
2723
|
+
```
|
2724
|
+
|
2725
|
+
[Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2726
|
+
|
2727
|
+
```ruby
|
2728
|
+
require 'glimmer-dsl-libui'
|
2729
|
+
|
2730
|
+
include Glimmer
|
2731
|
+
|
2732
|
+
window('Basic Area', 400, 400) {
|
2733
|
+
margined true
|
2734
|
+
|
2735
|
+
vertical_box {
|
2736
|
+
area {
|
2737
|
+
path { # a stable path is added declaratively
|
2738
|
+
rectangle(0, 0, 400, 400)
|
2739
|
+
|
2740
|
+
fill r: 102, g: 102, b: 204, a: 1.0
|
2741
|
+
}
|
2742
|
+
}
|
2743
|
+
}
|
2744
|
+
}.show
|
2745
|
+
```
|
2746
|
+
|
2747
|
+
### Dynamic Area
|
2748
|
+
|
2749
|
+
[examples/dynamic_area.rb](examples/dynamic_area.rb)
|
2750
|
+
|
2751
|
+
Run with this command from the root of the project if you cloned the project:
|
2752
|
+
|
2753
|
+
```
|
2754
|
+
ruby -r './lib/glimmer-dsl-libui' examples/dynamic_area.rb
|
2755
|
+
```
|
2756
|
+
|
2757
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
2758
|
+
|
2759
|
+
```
|
2760
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/dynamic_area'"
|
2761
|
+
```
|
2762
|
+
|
2763
|
+
Mac
|
2764
|
+
|
2765
|
+
![glimmer-dsl-libui-mac-dynamic-area.png](images/glimmer-dsl-libui-mac-dynamic-area.png)
|
2766
|
+
![glimmer-dsl-libui-mac-dynamic-area-updated.png](images/glimmer-dsl-libui-mac-dynamic-area-updated.png)
|
2767
|
+
|
2768
|
+
Linux
|
2769
|
+
|
2770
|
+
![glimmer-dsl-libui-linux-dynamic-area.png](images/glimmer-dsl-libui-linux-dynamic-area.png)
|
2771
|
+
![glimmer-dsl-libui-linux-dynamic-area-updated.png](images/glimmer-dsl-libui-linux-dynamic-area-updated.png)
|
2772
|
+
|
2773
|
+
New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
|
2774
|
+
|
2775
|
+
```ruby
|
2776
|
+
require 'glimmer-dsl-libui'
|
2777
|
+
|
2778
|
+
include Glimmer
|
2779
|
+
|
2780
|
+
window('Dynamic Area', 240, 500) {
|
2781
|
+
margined true
|
2782
|
+
|
2783
|
+
vertical_box {
|
2784
|
+
label('Rectangle Properties') {
|
2785
|
+
stretchy false
|
2786
|
+
}
|
2787
|
+
|
2788
|
+
form {
|
2789
|
+
stretchy false
|
2790
|
+
|
2791
|
+
@x_spinbox = spinbox(0, 1000) {
|
2792
|
+
label 'x'
|
2793
|
+
value 25
|
2794
|
+
|
2795
|
+
on_changed do
|
2796
|
+
@area.queue_redraw_all
|
2797
|
+
end
|
2798
|
+
}
|
2799
|
+
|
2800
|
+
@y_spinbox = spinbox(0, 1000) {
|
2801
|
+
label 'y'
|
2802
|
+
value 25
|
2803
|
+
|
2804
|
+
on_changed do
|
2805
|
+
@area.queue_redraw_all
|
2806
|
+
end
|
2807
|
+
}
|
2808
|
+
|
2809
|
+
@width_spinbox = spinbox(0, 1000) {
|
2810
|
+
label 'width'
|
2811
|
+
value 150
|
2812
|
+
|
2813
|
+
on_changed do
|
2814
|
+
@area.queue_redraw_all
|
2815
|
+
end
|
2816
|
+
}
|
2817
|
+
|
2818
|
+
@height_spinbox = spinbox(0, 1000) {
|
2819
|
+
label 'height'
|
2820
|
+
value 150
|
2821
|
+
|
2822
|
+
on_changed do
|
2823
|
+
@area.queue_redraw_all
|
2824
|
+
end
|
2825
|
+
}
|
2826
|
+
|
2827
|
+
@red_spinbox = spinbox(0, 255) {
|
2828
|
+
label 'red'
|
2829
|
+
value 102
|
2830
|
+
|
2831
|
+
on_changed do
|
2832
|
+
@area.queue_redraw_all
|
2833
|
+
end
|
2834
|
+
}
|
2835
|
+
|
2836
|
+
@green_spinbox = spinbox(0, 255) {
|
2837
|
+
label 'green'
|
2838
|
+
value 102
|
2839
|
+
|
2840
|
+
on_changed do
|
2841
|
+
@area.queue_redraw_all
|
2842
|
+
end
|
2843
|
+
}
|
2844
|
+
|
2845
|
+
@blue_spinbox = spinbox(0, 255) {
|
2846
|
+
label 'blue'
|
2847
|
+
value 204
|
2848
|
+
|
2849
|
+
on_changed do
|
2850
|
+
@area.queue_redraw_all
|
2851
|
+
end
|
2852
|
+
}
|
2853
|
+
|
2854
|
+
@alpha_spinbox = spinbox(0, 100) {
|
2855
|
+
label 'alpha'
|
2856
|
+
value 100
|
2857
|
+
|
2858
|
+
on_changed do
|
2859
|
+
@area.queue_redraw_all
|
2860
|
+
end
|
2861
|
+
}
|
2862
|
+
}
|
2863
|
+
|
2864
|
+
@area = area {
|
2865
|
+
on_draw do |area_draw_params|
|
2866
|
+
path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
|
2867
|
+
rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value)
|
2868
|
+
|
2869
|
+
fill r: @red_spinbox.value, g: @green_spinbox.value, b: @blue_spinbox.value, a: @alpha_spinbox.value / 100.0
|
2870
|
+
}
|
2871
|
+
end
|
2872
|
+
}
|
2873
|
+
}
|
2874
|
+
}.show
|
2875
|
+
```
|
2876
|
+
|
2467
2877
|
## Contributing to glimmer-dsl-libui
|
2468
2878
|
|
2469
2879
|
- Check out the latest master to make sure the feature hasn't been
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.1
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
|
3
|
+
include Glimmer
|
4
|
+
|
5
|
+
window('Basic Area', 400, 400) {
|
6
|
+
margined true
|
7
|
+
|
8
|
+
vertical_box {
|
9
|
+
area {
|
10
|
+
path { # a stable path is added declaratively
|
11
|
+
rectangle(0, 0, 400, 400)
|
12
|
+
|
13
|
+
fill r: 102, g: 102, b: 204, a: 1.0
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}.show
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
|
3
|
+
include Glimmer
|
4
|
+
|
5
|
+
window('Basic Area', 400, 400) {
|
6
|
+
margined true
|
7
|
+
|
8
|
+
vertical_box {
|
9
|
+
area {
|
10
|
+
on_draw do |area_draw_params|
|
11
|
+
path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
|
12
|
+
rectangle(0, 0, 400, 400)
|
13
|
+
|
14
|
+
fill r: 102, g: 102, b: 204, a: 1.0
|
15
|
+
}
|
16
|
+
end
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}.show
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
|
3
|
+
include Glimmer
|
4
|
+
|
5
|
+
window('Dynamic Area', 240, 600) {
|
6
|
+
margined true
|
7
|
+
|
8
|
+
vertical_box {
|
9
|
+
label('Rectangle Properties') {
|
10
|
+
stretchy false
|
11
|
+
}
|
12
|
+
|
13
|
+
form {
|
14
|
+
stretchy false
|
15
|
+
|
16
|
+
@x_spinbox = spinbox(0, 1000) {
|
17
|
+
label 'x'
|
18
|
+
value 25
|
19
|
+
|
20
|
+
on_changed do
|
21
|
+
@area.queue_redraw_all
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
@y_spinbox = spinbox(0, 1000) {
|
26
|
+
label 'y'
|
27
|
+
value 25
|
28
|
+
|
29
|
+
on_changed do
|
30
|
+
@area.queue_redraw_all
|
31
|
+
end
|
32
|
+
}
|
33
|
+
|
34
|
+
@width_spinbox = spinbox(0, 1000) {
|
35
|
+
label 'width'
|
36
|
+
value 150
|
37
|
+
|
38
|
+
on_changed do
|
39
|
+
@area.queue_redraw_all
|
40
|
+
end
|
41
|
+
}
|
42
|
+
|
43
|
+
@height_spinbox = spinbox(0, 1000) {
|
44
|
+
label 'height'
|
45
|
+
value 150
|
46
|
+
|
47
|
+
on_changed do
|
48
|
+
@area.queue_redraw_all
|
49
|
+
end
|
50
|
+
}
|
51
|
+
|
52
|
+
@red_spinbox = spinbox(0, 255) {
|
53
|
+
label 'red'
|
54
|
+
value 102
|
55
|
+
|
56
|
+
on_changed do
|
57
|
+
@area.queue_redraw_all
|
58
|
+
end
|
59
|
+
}
|
60
|
+
|
61
|
+
@green_spinbox = spinbox(0, 255) {
|
62
|
+
label 'green'
|
63
|
+
value 102
|
64
|
+
|
65
|
+
on_changed do
|
66
|
+
@area.queue_redraw_all
|
67
|
+
end
|
68
|
+
}
|
69
|
+
|
70
|
+
@blue_spinbox = spinbox(0, 255) {
|
71
|
+
label 'blue'
|
72
|
+
value 204
|
73
|
+
|
74
|
+
on_changed do
|
75
|
+
@area.queue_redraw_all
|
76
|
+
end
|
77
|
+
}
|
78
|
+
|
79
|
+
@alpha_spinbox = spinbox(0, 100) {
|
80
|
+
label 'alpha'
|
81
|
+
value 100
|
82
|
+
|
83
|
+
on_changed do
|
84
|
+
@area.queue_redraw_all
|
85
|
+
end
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
@area = area {
|
90
|
+
on_draw do |area_draw_params|
|
91
|
+
path(area_draw_params) { # a dynamic path is added semi-declaratively inside on_draw block
|
92
|
+
rectangle(@x_spinbox.value, @y_spinbox.value, @width_spinbox.value, @height_spinbox.value)
|
93
|
+
|
94
|
+
fill r: @red_spinbox.value, g: @green_spinbox.value, b: @blue_spinbox.value, a: @alpha_spinbox.value / 100.0
|
95
|
+
}
|
96
|
+
end
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}.show
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
|
5
|
+
include Glimmer
|
6
|
+
|
7
|
+
data = [
|
8
|
+
['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
|
9
|
+
['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
|
10
|
+
['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
|
11
|
+
['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
|
12
|
+
['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
|
13
|
+
]
|
14
|
+
|
15
|
+
window('Contacts', 600, 600) { |w|
|
16
|
+
margined true
|
17
|
+
|
18
|
+
vertical_box {
|
19
|
+
form {
|
20
|
+
stretchy false
|
21
|
+
|
22
|
+
@name_entry = entry {
|
23
|
+
label 'Name'
|
24
|
+
}
|
25
|
+
@email_entry = entry {
|
26
|
+
label 'Email'
|
27
|
+
}
|
28
|
+
@phone_entry = entry {
|
29
|
+
label 'Phone'
|
30
|
+
}
|
31
|
+
@city_entry = entry {
|
32
|
+
label 'City'
|
33
|
+
}
|
34
|
+
@state_entry = entry {
|
35
|
+
label 'State'
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
button('Save Contact') {
|
40
|
+
stretchy false
|
41
|
+
|
42
|
+
on_clicked do
|
43
|
+
new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
|
44
|
+
if new_row.include?('')
|
45
|
+
msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
|
46
|
+
else
|
47
|
+
data << new_row # automatically inserts a row into the table due to implicit data-binding
|
48
|
+
@name_entry.text = ''
|
49
|
+
@email_entry.text = ''
|
50
|
+
@phone_entry.text = ''
|
51
|
+
@city_entry.text = ''
|
52
|
+
@state_entry.text = ''
|
53
|
+
end
|
54
|
+
end
|
55
|
+
}
|
56
|
+
|
57
|
+
table {
|
58
|
+
text_column('Name')
|
59
|
+
text_column('Email')
|
60
|
+
text_column('Phone')
|
61
|
+
text_column('City')
|
62
|
+
text_column('State')
|
63
|
+
|
64
|
+
cell_rows data # implicit data-binding
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}.show
|
data/glimmer-dsl-libui.gemspec
CHANGED
Binary file
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Copyright (c) 2021 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
module Glimmer
|
23
|
+
module FiddleConsumer
|
24
|
+
# Protects Fiddle::Closure::BlockCaller objects from garbage collection.
|
25
|
+
def fiddle_closure_block_caller(*args, &block)
|
26
|
+
@blockcaller ||= []
|
27
|
+
args << [0] if args.size == 1 # Argument types are ommited
|
28
|
+
blockcaller = ::Fiddle::Closure::BlockCaller.new(*args, &block)
|
29
|
+
@blockcaller << blockcaller
|
30
|
+
blockcaller
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# Copyright (c) 2021 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'glimmer/libui/control_proxy'
|
23
|
+
require 'glimmer/fiddle_consumer'
|
24
|
+
|
25
|
+
module Glimmer
|
26
|
+
module LibUI
|
27
|
+
# Proxy for LibUI area objects
|
28
|
+
#
|
29
|
+
# Follows the Proxy Design Pattern
|
30
|
+
class AreaProxy < ControlProxy
|
31
|
+
include Glimmer::FiddleConsumer
|
32
|
+
|
33
|
+
attr_reader :area_handler
|
34
|
+
|
35
|
+
def post_initialize_child(child)
|
36
|
+
super
|
37
|
+
children << child
|
38
|
+
end
|
39
|
+
|
40
|
+
def post_add_content
|
41
|
+
super
|
42
|
+
install_listeners
|
43
|
+
end
|
44
|
+
|
45
|
+
def children
|
46
|
+
@children ||= []
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_draw(&block)
|
50
|
+
@on_draw_procs ||= []
|
51
|
+
if block.nil?
|
52
|
+
@on_draw_procs
|
53
|
+
else
|
54
|
+
@on_draw_procs << block
|
55
|
+
block
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def can_handle_listener?(listener_name)
|
60
|
+
listener_name == 'on_draw' || super
|
61
|
+
end
|
62
|
+
|
63
|
+
def handle_listener(listener_name, &listener)
|
64
|
+
case listener_name
|
65
|
+
when 'on_draw'
|
66
|
+
on_draw(&listener)
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def build_control
|
75
|
+
@area_handler = ::LibUI::FFI::AreaHandler.malloc
|
76
|
+
@libui = ::LibUI.new_area(@area_handler)
|
77
|
+
end
|
78
|
+
|
79
|
+
def install_listeners
|
80
|
+
@area_handler.Draw = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_draw_params|
|
81
|
+
area_draw_params = ::LibUI::FFI::AreaDrawParams.new(area_draw_params)
|
82
|
+
area_draw_params = area_draw_params_hash(area_draw_params)
|
83
|
+
children.each {|child| child.draw(area_draw_params)}
|
84
|
+
on_draw.each {|listener| listener.call(area_draw_params) }
|
85
|
+
end
|
86
|
+
@area_handler.MouseEvent = fiddle_closure_block_caller(0, [0]) {}
|
87
|
+
@area_handler.MouseCrossed = fiddle_closure_block_caller(0, [0]) {}
|
88
|
+
@area_handler.DragBroken = fiddle_closure_block_caller(0, [0]) {}
|
89
|
+
@area_handler.KeyEvent = fiddle_closure_block_caller(0, [0]) {}
|
90
|
+
end
|
91
|
+
|
92
|
+
def area_draw_params_hash(area_draw_params)
|
93
|
+
{
|
94
|
+
context: area_draw_params.Context,
|
95
|
+
area_width: area_draw_params.AreaWidth,
|
96
|
+
area_height: area_draw_params.AreaHeight,
|
97
|
+
clip_x: area_draw_params.ClipX,
|
98
|
+
clip_y: area_draw_params.ClipY,
|
99
|
+
clip_width: area_draw_params.ClipWidth,
|
100
|
+
clip_height: area_draw_params.ClipHeight,
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -35,7 +35,12 @@ module Glimmer
|
|
35
35
|
def on_clicked(&block)
|
36
36
|
# TODO consider generalizing into custom listeners and moving to ControlProxy
|
37
37
|
@on_clicked_procs ||= []
|
38
|
-
|
38
|
+
if block.nil?
|
39
|
+
@on_clicked_procs
|
40
|
+
else
|
41
|
+
@on_clicked_procs << block
|
42
|
+
block
|
43
|
+
end
|
39
44
|
end
|
40
45
|
|
41
46
|
def can_handle_listener?(listener_name)
|
@@ -30,12 +30,12 @@ module Glimmer
|
|
30
30
|
# Follows the Proxy Design Pattern
|
31
31
|
class CheckboxColumnProxy < ControlProxy
|
32
32
|
include Column
|
33
|
-
|
33
|
+
include EditableColumn
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
37
|
def build_control
|
38
|
-
@parent_proxy.append_checkbox_column(name, column_index,
|
38
|
+
@parent_proxy.append_checkbox_column(name, column_index, editable_value)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -32,12 +32,44 @@ module Glimmer
|
|
32
32
|
class CheckboxTextColumnProxy < ControlProxy
|
33
33
|
include Column
|
34
34
|
include DualColumn
|
35
|
-
include EditableColumn
|
35
|
+
include EditableColumn
|
36
36
|
|
37
|
+
def editable_checkbox(value = nil)
|
38
|
+
if value.nil?
|
39
|
+
@editable_checkbox = false if @editable_checkbox.nil?
|
40
|
+
@editable_checkbox
|
41
|
+
else
|
42
|
+
@editable_checkbox = !!value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
alias editable_checkbox= editable_checkbox
|
46
|
+
alias set_editable_checkbox editable_checkbox
|
47
|
+
alias editable_checkbox? editable_checkbox
|
48
|
+
|
49
|
+
def editable_text(value = nil)
|
50
|
+
if value.nil?
|
51
|
+
@editable_text = false if @editable_text.nil?
|
52
|
+
@editable_text
|
53
|
+
else
|
54
|
+
@editable_text = !!value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
alias editable_text= editable_text
|
58
|
+
alias set_editable_text editable_text
|
59
|
+
alias editable_text? editable_text
|
60
|
+
|
37
61
|
private
|
38
62
|
|
39
63
|
def build_control
|
40
|
-
@parent_proxy.append_checkbox_text_column(name, column_index,
|
64
|
+
@parent_proxy.append_checkbox_text_column(name, column_index, editable_checkbox_value, second_column_index, editable_text_value)
|
65
|
+
end
|
66
|
+
|
67
|
+
def editable_checkbox_value
|
68
|
+
(@parent_proxy.editable? || editable? || editable_checkbox?) ? -2 : -1
|
69
|
+
end
|
70
|
+
|
71
|
+
def editable_text_value
|
72
|
+
(@parent_proxy.editable? || editable? || editable_text?) ? -2 : -1
|
41
73
|
end
|
42
74
|
end
|
43
75
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# Copyright (c) 2021 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'glimmer/libui/control_proxy'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module LibUI
|
26
|
+
# Proxy for LibUI path objects
|
27
|
+
#
|
28
|
+
# Follows the Proxy Design Pattern
|
29
|
+
class PathProxy < ControlProxy
|
30
|
+
# TODO support mode without parent proxy
|
31
|
+
def initialize(keyword, parent, args, &block)
|
32
|
+
@keyword = keyword
|
33
|
+
@parent_proxy = parent
|
34
|
+
@args = args
|
35
|
+
@block = block
|
36
|
+
@enabled = true
|
37
|
+
post_add_content if @block.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def post_initialize_child(child)
|
41
|
+
super
|
42
|
+
children << child
|
43
|
+
end
|
44
|
+
|
45
|
+
def post_add_content
|
46
|
+
super
|
47
|
+
draw(area_draw_params) if @parent_proxy.nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def children
|
51
|
+
@children ||= []
|
52
|
+
end
|
53
|
+
|
54
|
+
def draw(area_draw_params)
|
55
|
+
build_control
|
56
|
+
children.each {|child| child.draw(area_draw_params)}
|
57
|
+
::LibUI.draw_path_end(@libui)
|
58
|
+
::LibUI.draw_fill(area_draw_params[:context], @libui, fill_draw_brush.to_ptr) unless fill.empty?
|
59
|
+
::LibUI.draw_stroke(area_draw_params[:context], @libui, stroke_draw_brush, draw_stroke_params) unless stroke.empty?
|
60
|
+
::LibUI.draw_free_path(@libui)
|
61
|
+
end
|
62
|
+
|
63
|
+
def draw_fill_mode
|
64
|
+
@args[0].is_a?(Integer) ? @args[0] : @args[0].to_s == 'alternate' ? 1 : 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def fill(args = nil)
|
68
|
+
if args.nil?
|
69
|
+
@fill ||= {}
|
70
|
+
else
|
71
|
+
@fill = args
|
72
|
+
end
|
73
|
+
end
|
74
|
+
alias fill= fill
|
75
|
+
alias set_fill fill
|
76
|
+
|
77
|
+
def fill_draw_brush
|
78
|
+
@fill_draw_brush ||= ::LibUI::FFI::DrawBrush.malloc
|
79
|
+
init_draw_brush(@fill_draw_brush, @fill)
|
80
|
+
@fill_draw_brush
|
81
|
+
end
|
82
|
+
|
83
|
+
def stroke(args = nil)
|
84
|
+
if args.nil?
|
85
|
+
@stroke ||= {}
|
86
|
+
else
|
87
|
+
@stroke = args
|
88
|
+
end
|
89
|
+
end
|
90
|
+
alias stroke= stroke
|
91
|
+
alias set_stroke stroke
|
92
|
+
|
93
|
+
def stroke_draw_brush
|
94
|
+
@stroke_draw_brush ||= ::LibUI::FFI::DrawBrush.malloc
|
95
|
+
init_draw_brush(@stroke_draw_brush, @stroke)
|
96
|
+
@stroke_draw_brush
|
97
|
+
end
|
98
|
+
|
99
|
+
def draw_stroke_params
|
100
|
+
@draw_stroke_params ||= ::LibUI::FFI::DrawStrokeParams.malloc
|
101
|
+
@draw_stroke_params.Cap = @stroke[:cap] || 0 # flat
|
102
|
+
@draw_stroke_params.Join = @stroke[:join] || 0 # miter
|
103
|
+
@draw_stroke_params.Thickness = @stroke[:thickness] || 1
|
104
|
+
@draw_stroke_params.MiterLimit = @stroke[:miter_limit] || 10 # DEFAULT_MITER_LIMIT
|
105
|
+
@draw_stroke_params_dashes ||= Fiddle::Pointer.malloc(8)
|
106
|
+
@draw_stroke_params.Dashes = @draw_stroke_params_dashes
|
107
|
+
@draw_stroke_params.NumDashes = @stroke[:num_dashes] || 0 # TODO reimplement this line correctly (perhaps no need to pass num dashes, yet dashes themselves and use their count here)
|
108
|
+
@draw_stroke_params.DashPhase = @stroke[:dash_phase] || 0
|
109
|
+
@draw_stroke_params
|
110
|
+
end
|
111
|
+
|
112
|
+
# returns area_draw_params if built inside on_draw listener (not needed if declared outside)
|
113
|
+
def area_draw_params
|
114
|
+
@args[0] if @parent_proxy.nil?
|
115
|
+
end
|
116
|
+
|
117
|
+
def destroy
|
118
|
+
@parent_proxy.children.delete(self) unless @parent_proxy.nil?
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def build_control
|
124
|
+
@libui = ::LibUI.draw_new_path(draw_fill_mode)
|
125
|
+
end
|
126
|
+
|
127
|
+
def init_draw_brush(draw_brush, draw_brush_args)
|
128
|
+
case draw_brush_args[:type]
|
129
|
+
when Integer
|
130
|
+
draw_brush.Type = draw_brush_args[:type]
|
131
|
+
when :solid, 'solid'
|
132
|
+
draw_brush.Type = 0
|
133
|
+
when :linear_gradient, 'linear_gradient'
|
134
|
+
draw_brush.Type = 1
|
135
|
+
when :radial_gradient, 'radial_gradient'
|
136
|
+
draw_brush.Type = 2
|
137
|
+
when :image, 'image'
|
138
|
+
draw_brush.Type = 3
|
139
|
+
else
|
140
|
+
draw_brush.Type = 0
|
141
|
+
end
|
142
|
+
draw_brush.R = (draw_brush_args[:r] || draw_brush_args[:red]).to_f / 255.0
|
143
|
+
draw_brush.G = (draw_brush_args[:g] || draw_brush_args[:green]).to_f / 255.0
|
144
|
+
draw_brush.B = (draw_brush_args[:b] || draw_brush_args[:blue]).to_f / 255.0
|
145
|
+
draw_brush.A = (draw_brush_args[:a] || draw_brush_args[:alpha])
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Copyright (c) 2021 Andy Maleh
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
# a copy of this software and associated documentation files (the
|
5
|
+
# "Software"), to deal in the Software without restriction, including
|
6
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
# the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be
|
12
|
+
# included in all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
require 'glimmer/libui/control_proxy'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module LibUI
|
26
|
+
# Proxy for LibUI rectangle objects
|
27
|
+
#
|
28
|
+
# Follows the Proxy Design Pattern
|
29
|
+
class RectangleProxy < ControlProxy
|
30
|
+
def initialize(keyword, parent, args, &block)
|
31
|
+
@keyword = keyword
|
32
|
+
@parent_proxy = parent
|
33
|
+
@args = args
|
34
|
+
@block = block
|
35
|
+
@enabled = true
|
36
|
+
post_add_content if @block.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def draw(area_draw_params)
|
40
|
+
::LibUI.draw_path_add_rectangle(@parent_proxy.libui, *@args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy
|
44
|
+
if @parent_proxy
|
45
|
+
@parent_proxy.children.delete(self)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def build_control
|
52
|
+
# No Op
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -21,6 +21,7 @@
|
|
21
21
|
|
22
22
|
require 'glimmer/libui/control_proxy'
|
23
23
|
require 'glimmer/data_binding/observer'
|
24
|
+
require 'glimmer/fiddle_consumer'
|
24
25
|
|
25
26
|
using ArrayIncludeMethods
|
26
27
|
|
@@ -30,6 +31,8 @@ module Glimmer
|
|
30
31
|
#
|
31
32
|
# Follows the Proxy Design Pattern
|
32
33
|
class TableProxy < ControlProxy
|
34
|
+
include Glimmer::FiddleConsumer
|
35
|
+
|
33
36
|
attr_reader :model_handler, :model, :table_params, :columns
|
34
37
|
|
35
38
|
def initialize(keyword, parent, args, &block)
|
@@ -71,8 +74,16 @@ module Glimmer
|
|
71
74
|
@last_cell_rows = @cell_rows.clone
|
72
75
|
Glimmer::DataBinding::Observer.proc do
|
73
76
|
if @cell_rows.size < @last_cell_rows.size && @last_cell_rows.include_all?(*@cell_rows)
|
74
|
-
@last_cell_rows.array_diff_indexes(@cell_rows).reverse.each do |
|
75
|
-
::LibUI.table_model_row_deleted(model,
|
77
|
+
@last_cell_rows.array_diff_indexes(@cell_rows).reverse.each do |row|
|
78
|
+
::LibUI.table_model_row_deleted(model, row)
|
79
|
+
end
|
80
|
+
elsif @cell_rows.size > @last_cell_rows.size && @cell_rows.include_all?(*@last_cell_rows)
|
81
|
+
@cell_rows.array_diff_indexes(@last_cell_rows).each do |row|
|
82
|
+
::LibUI.table_model_row_inserted(model, row)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
@cell_rows.each_with_index do |new_row_data, row|
|
86
|
+
::LibUI.table_model_row_changed(model, row) if new_row_data != @last_cell_rows[row]
|
76
87
|
end
|
77
88
|
end
|
78
89
|
@last_cell_rows = @cell_rows.clone
|
@@ -104,8 +115,8 @@ module Glimmer
|
|
104
115
|
|
105
116
|
def build_control
|
106
117
|
@model_handler = ::LibUI::FFI::TableModelHandler.malloc
|
107
|
-
@model_handler.NumColumns =
|
108
|
-
@model_handler.ColumnType =
|
118
|
+
@model_handler.NumColumns = fiddle_closure_block_caller(4) { @columns.map {|c| c.is_a?(DualColumn) ? 2 : 1}.sum }
|
119
|
+
@model_handler.ColumnType = fiddle_closure_block_caller(4, [1, 1, 4]) do |_, _, column|
|
109
120
|
case @columns[column]
|
110
121
|
when TextColumnProxy, ButtonColumnProxy, NilClass
|
111
122
|
0
|
@@ -115,8 +126,8 @@ module Glimmer
|
|
115
126
|
2
|
116
127
|
end
|
117
128
|
end
|
118
|
-
@model_handler.NumRows =
|
119
|
-
@model_handler.CellValue =
|
129
|
+
@model_handler.NumRows = fiddle_closure_block_caller(4) { cell_rows.count }
|
130
|
+
@model_handler.CellValue = fiddle_closure_block_caller(1, [1, 1, 4, 4]) do |_, _, row, column|
|
120
131
|
the_cell_rows = expanded_cell_rows
|
121
132
|
case @columns[column]
|
122
133
|
when TextColumnProxy, ButtonColumnProxy, NilClass
|
@@ -129,7 +140,7 @@ module Glimmer
|
|
129
140
|
::LibUI.new_table_value_int((expanded_cell_rows[row] && (expanded_cell_rows[row][column].to_i)))
|
130
141
|
end
|
131
142
|
end
|
132
|
-
@model_handler.SetCellValue =
|
143
|
+
@model_handler.SetCellValue = fiddle_closure_block_caller(0, [1, 1, 4, 4, 1]) do |_, _, row, column, val|
|
133
144
|
case @columns[column]
|
134
145
|
when TextColumnProxy
|
135
146
|
column = @columns[column].index
|
@@ -159,16 +170,6 @@ module Glimmer
|
|
159
170
|
end
|
160
171
|
end
|
161
172
|
|
162
|
-
def rbcallback(*args, &block)
|
163
|
-
# TODO consider moving to a more general reusable location in the future (e.g. when used with `AreaProxy`)
|
164
|
-
# Protects BlockCaller objects from garbage collection.
|
165
|
-
@blockcaller ||= []
|
166
|
-
args << [0] if args.size == 1 # Argument types are ommited
|
167
|
-
blockcaller = Fiddle::Closure::BlockCaller.new(*args, &block)
|
168
|
-
@blockcaller << blockcaller
|
169
|
-
blockcaller
|
170
|
-
end
|
171
|
-
|
172
173
|
def next_column_index
|
173
174
|
@next_column_index ||= -1
|
174
175
|
@next_column_index += 1
|
@@ -48,8 +48,14 @@ module Glimmer
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def on_destroy(&block)
|
51
|
+
# TODO look into a way to generalize this logic for multiple listeners
|
51
52
|
@on_destroy_procs ||= []
|
52
|
-
|
53
|
+
if block.nil?
|
54
|
+
@on_destroy_procs
|
55
|
+
else
|
56
|
+
@on_destroy_procs << block
|
57
|
+
block
|
58
|
+
end
|
53
59
|
end
|
54
60
|
|
55
61
|
def show
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer-dsl-libui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -194,6 +194,8 @@ files:
|
|
194
194
|
- VERSION
|
195
195
|
- bin/girb
|
196
196
|
- bin/girb_runner.rb
|
197
|
+
- examples/basic_area.rb
|
198
|
+
- examples/basic_area2.rb
|
197
199
|
- examples/basic_button.rb
|
198
200
|
- examples/basic_entry.rb
|
199
201
|
- examples/basic_table.rb
|
@@ -208,10 +210,12 @@ files:
|
|
208
210
|
- examples/color_button.rb
|
209
211
|
- examples/control_gallery.rb
|
210
212
|
- examples/date_time_picker.rb
|
213
|
+
- examples/dynamic_area.rb
|
211
214
|
- examples/editable_column_table.rb
|
212
215
|
- examples/editable_table.rb
|
213
216
|
- examples/font_button.rb
|
214
217
|
- examples/form.rb
|
218
|
+
- examples/form_table.rb
|
215
219
|
- examples/grid.rb
|
216
220
|
- examples/meta_example.rb
|
217
221
|
- examples/midi_player.rb
|
@@ -226,7 +230,9 @@ files:
|
|
226
230
|
- lib/glimmer/dsl/libui/property_expression.rb
|
227
231
|
- lib/glimmer/dsl/libui/save_file_expression.rb
|
228
232
|
- lib/glimmer/dsl/libui/tab_item_expression.rb
|
233
|
+
- lib/glimmer/fiddle_consumer.rb
|
229
234
|
- lib/glimmer/libui/about_menu_item_proxy.rb
|
235
|
+
- lib/glimmer/libui/area_proxy.rb
|
230
236
|
- lib/glimmer/libui/box.rb
|
231
237
|
- lib/glimmer/libui/button_column_proxy.rb
|
232
238
|
- lib/glimmer/libui/button_proxy.rb
|
@@ -258,10 +264,12 @@ files:
|
|
258
264
|
- lib/glimmer/libui/menu_proxy.rb
|
259
265
|
- lib/glimmer/libui/multiline_entry_proxy.rb
|
260
266
|
- lib/glimmer/libui/non_wrapping_multiline_entry_proxy.rb
|
267
|
+
- lib/glimmer/libui/path_proxy.rb
|
261
268
|
- lib/glimmer/libui/preferences_menu_item_proxy.rb
|
262
269
|
- lib/glimmer/libui/progress_bar_column_proxy.rb
|
263
270
|
- lib/glimmer/libui/quit_menu_item_proxy.rb
|
264
271
|
- lib/glimmer/libui/radio_buttons_proxy.rb
|
272
|
+
- lib/glimmer/libui/rectangle_proxy.rb
|
265
273
|
- lib/glimmer/libui/separator_menu_item_proxy.rb
|
266
274
|
- lib/glimmer/libui/tab_item_proxy.rb
|
267
275
|
- lib/glimmer/libui/table_proxy.rb
|