glimmer-dsl-libui 0.0.26 → 0.1.1
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/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
|
[](http://badge.fury.io/rb/glimmer-dsl-libui)
|
4
4
|
[](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
|
+

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

|
2572
|
+

|
2573
|
+
|
2574
|
+
Linux
|
2575
|
+
|
2576
|
+

|
2577
|
+

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

|
2668
|
+
|
2669
|
+
Linux
|
2670
|
+
|
2671
|
+

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

|
2766
|
+

|
2767
|
+
|
2768
|
+
Linux
|
2769
|
+
|
2770
|
+

|
2771
|
+

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