glimmer-dsl-libui 0.10.1 → 0.11.0
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 +13 -1
- data/README.md +75 -10
- data/VERSION +1 -1
- data/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md +28 -0
- data/examples/button_counter.rb +18 -11
- data/examples/dynamic_form.rb +69 -0
- data/examples/snake/model/snake.rb +43 -17
- data/examples/snake.rb +6 -2
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/dsl/libui/content_expression.rb +41 -0
- data/lib/glimmer/dsl/libui/dsl.rb +1 -0
- data/lib/glimmer/libui/control_proxy.rb +13 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: effb65102f9db3aa2977bac55edd4f67f91f1eafdae26403b8c044c714048a03
|
4
|
+
data.tar.gz: 3923d80a19afd62a0220026f33720ee953ad166880e17d60883aed53f9977d86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e123f42fd61ce49b126e7f51caf738e0c769eca12b177c879007cedaba6ec38974d16ca864e8d8922546f79cfe2dc8946056935684f0bab9d88892e425c5d79
|
7
|
+
data.tar.gz: 8d0d79d7632e30568f747a3db5d9bbdef387e854f55e0cf6559a4d8d242075bc8c1836e00e2554a30eb5eded934bb23c267a764b127cfe768c39e679ff47671e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.11.0
|
4
|
+
|
5
|
+
- Control `content` data-binding to generate nested controls dynamically based on a model attribute change
|
6
|
+
- `examples/dynamic_form.rb` to demonstrate control `content` data-binding
|
7
|
+
|
8
|
+
## 0.10.2
|
9
|
+
|
10
|
+
- In Snake example, change snake direction on key press instead of key release to be more responsive for players who are not used to releasing pressed keys quickly
|
11
|
+
- In Snake example, fix issue with detecting collision too soon if a snake fills the entire space horizontally or vertically
|
12
|
+
- In Snake example, fix issue of hearing beeps on every direction change because of not properly informing LibUI when the area key down event is handled
|
13
|
+
- In Snake example, refactor `Snake::Model::Snake` to be more readable like high-level game domain rules (especially `move` method)
|
14
|
+
|
3
15
|
## 0.10.1
|
4
16
|
|
5
17
|
- Scaffold custom shape
|
@@ -8,7 +20,7 @@
|
|
8
20
|
|
9
21
|
## 0.10.0
|
10
22
|
|
11
|
-
- Support Custom Shapes
|
23
|
+
- Support Custom Shapes by mixing in `Glimmer::LibUI::CustomShape` to abstract composite shapes/text/image concepts inside an `area`
|
12
24
|
- `examples/basic_custom_shape.rb` example
|
13
25
|
- Support nesting listeners under a Custom Shape that will automatically get added to its `body_root` control
|
14
26
|
- Support nesting listeners under a Custom Control that will automatically get added to its `body_root` control
|
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.11.0
|
2
2
|
## Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library ([Fukuoka Award Winning](http://www.digitalfukuoka.jp/topics/187?locale=ja))
|
3
3
|
### The Quickest Way From Zero To GUI
|
4
4
|
[](http://badge.fury.io/rb/glimmer-dsl-libui)
|
@@ -431,7 +431,7 @@ gem install glimmer-dsl-libui
|
|
431
431
|
Or install via Bundler `Gemfile`:
|
432
432
|
|
433
433
|
```ruby
|
434
|
-
gem 'glimmer-dsl-libui', '~> 0.
|
434
|
+
gem 'glimmer-dsl-libui', '~> 0.11.0'
|
435
435
|
```
|
436
436
|
|
437
437
|
Test that installation worked by running the [Glimmer Meta-Example](#examples):
|
@@ -452,8 +452,19 @@ Mac | Windows | Linux
|
|
452
452
|
|
453
453
|
## Usage
|
454
454
|
|
455
|
-
|
456
|
-
|
455
|
+
Start by requiring the [glimmer-dsl-libui](https://rubygems.org/gems/glimmer-dsl-libui) Ruby gem, whether through a Ruby `require 'glimmer-dsl-libui` statement or `Bundler`.
|
456
|
+
|
457
|
+
Afterwards, to access the Glimmer GUI DSL:
|
458
|
+
- If you are learning/experimenting/prototyping with Glimmer DSL for LibUI, include the `Glimmer` module into the top-level scope or a Ruby class.
|
459
|
+
- If you are building a serious application, include `Glimmer::LibUI::Application` into the main view Ruby class
|
460
|
+
- If you are building a custom control, include [`Glimmer::LibUI::CustomControl`](#custom-components) into a Ruby class
|
461
|
+
- If you are building a cusotm window, include [`Glimmer::LibUI::CustomWindow`](#custom-components) into a Ruby class
|
462
|
+
- If you are building a custom shape, include [`Glimmer::LibUI::CustomShape`](#custom-components) into a Ruby class.
|
463
|
+
|
464
|
+
You may learn more about the different options above with basic examples in the following subsections: [Experimentation Usage](#experimentation-usage), [Prototyping Usage](#prototyping-usage), [Serious Usage](#serious-usage).
|
465
|
+
|
466
|
+
If you are new to [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) (beginner), after going through the subsections below, check out the RubyConf 2022 talk ["Building Native GUI Apps in Ruby"](https://andymaleh.blogspot.com/2023/02/rubyconf-2022-talk-video-for-building.html), [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts), [Glimmer Command](#glimmer-command) (just the basics, how to run an app, and how to run examples to start), [Girb](#girb-glimmer-irb) and [Examples](#examples) to quickly learn through copy/paste. It is very important for beginners to go through all the [Examples](#examples) from the most basic to the most advanced while reading the README topics that relate to the examples. You may refer to the [API](#api) on once you have gotten your feet wet with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) and need more detailed reference information.
|
467
|
+
|
457
468
|
### Experimentation Usage
|
458
469
|
|
459
470
|
For experimenting and learning, add `include Glimmer` into the top-level main object and start using the Glimmer GUI DSL directly.
|
@@ -534,9 +545,6 @@ SomeGlimmerApp.launch
|
|
534
545
|
|
535
546
|
(note: `Glimmer::LibUI::Application` is an alias for `Glimmer::LibUI::CustomWindow` since that is what it represents)
|
536
547
|
|
537
|
-
If you are new to [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui), check out the [Glimmer GUI DSL Concepts](#glimmer-gui-dsl-concepts), [Glimmer Command](#glimmer-command), [Girb](#girb-glimmer-irb) and [Examples](#examples) to quickly learn through copy/paste. You may refer to the [API](#api) later on once you have gotten your feet wet with [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) and need more detailed reference information.
|
538
|
-
|
539
|
-
|
540
548
|
## Glimmer Command
|
541
549
|
|
542
550
|
The `glimmer` command allows you to conveniently run applications (`glimmer app_path`), run examples (`glimmer examples`), and scaffold applications (`glimmer "scaffold[app_name]"`).
|
@@ -548,7 +556,6 @@ glimmer
|
|
548
556
|
```
|
549
557
|
|
550
558
|
```
|
551
|
-
% bin/glimmer
|
552
559
|
Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library) - Ruby Gem: glimmer-dsl-libui v0.8.0
|
553
560
|
|
554
561
|
Usage: glimmer [--bundler] [--pd] [--quiet] [--debug] [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-ruby-option]...] (application.rb or task[task_args])
|
@@ -1592,6 +1599,43 @@ button('greet') { |b|
|
|
1592
1599
|
}
|
1593
1600
|
```
|
1594
1601
|
|
1602
|
+
If there is ever a need to add more content to a control, you can re-open its content with the `control.content { ... }` method.
|
1603
|
+
|
1604
|
+
Example:
|
1605
|
+
|
1606
|
+
```ruby
|
1607
|
+
box1 = vertical_box {
|
1608
|
+
label('First Name')
|
1609
|
+
}
|
1610
|
+
# re-open content of box1 and add another control
|
1611
|
+
box1.content {
|
1612
|
+
entry {
|
1613
|
+
text 'fill in your first name'
|
1614
|
+
}
|
1615
|
+
}
|
1616
|
+
```
|
1617
|
+
|
1618
|
+
You can also use [data-binding](#data-binding) with content blocks to generate content dynamically based on changes in a model attribute. The only difference in syntax in this case would be to wrap the content with an explicit `content(*binding_args) { ... }` block that includes data-binding arguments for a model attribute.
|
1619
|
+
|
1620
|
+
Example:
|
1621
|
+
|
1622
|
+
```ruby
|
1623
|
+
form {
|
1624
|
+
stretchy false
|
1625
|
+
|
1626
|
+
content(@user, :customizable_attributes) {
|
1627
|
+
@user.customizable_attributes.each do |attribute|
|
1628
|
+
entry {
|
1629
|
+
label attribute.to_s.split('_').map(&:capitalize).join(' ')
|
1630
|
+
text <=> [@user, attribute]
|
1631
|
+
}
|
1632
|
+
end
|
1633
|
+
}
|
1634
|
+
}
|
1635
|
+
```
|
1636
|
+
|
1637
|
+
The form above will only display fields for a model's customizable attributes, so if they change, the form content will change too. Learn more at the [Dynamic Form](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#dynamic-form) example.
|
1638
|
+
|
1595
1639
|
**Property**: Control properties may be declared inside keyword blocks with lower-case underscored name followed by property value args (e.g. `title "hello world"` inside `group`). Behind the scenes, properties correspond to `LibUI.control_set_property` methods.
|
1596
1640
|
|
1597
1641
|
**Listener**: Control listeners may be declared inside keyword blocks with listener lower-case underscored name beginning with `on_` and receiving required block handler (always followed by a `do; end` style block to signify logic).
|
@@ -3388,11 +3432,11 @@ Another example of bidirectional data-binding with an option:
|
|
3388
3432
|
|
3389
3433
|
```ruby
|
3390
3434
|
entry {
|
3391
|
-
text <=> [
|
3435
|
+
text <=> [model, :entered_text, after_write: ->(text) {puts text}]
|
3392
3436
|
}
|
3393
3437
|
```
|
3394
3438
|
|
3395
|
-
That is data-binding `entered_text` attribute on `
|
3439
|
+
That is data-binding `entered_text` attribute on `model` to `entry` `text` property and printing text after write to the model.
|
3396
3440
|
|
3397
3441
|
##### Table Data-Binding
|
3398
3442
|
|
@@ -3574,6 +3618,27 @@ window {
|
|
3574
3618
|
|
3575
3619
|
That is data-binding the `window` `title` property to the `score` attribute of a `@game`, but converting on read from the Model to a `String`.
|
3576
3620
|
|
3621
|
+
You can also use unidirectional [data-binding](#data-binding) with content blocks to generate content dynamically based on changes in a model attribute. The only difference in syntax in this case would be to wrap the content with an explicit `content(*binding_args) { ... }` block that includes data-binding arguments for a model attribute.
|
3622
|
+
|
3623
|
+
Example:
|
3624
|
+
|
3625
|
+
```ruby
|
3626
|
+
form {
|
3627
|
+
stretchy false
|
3628
|
+
|
3629
|
+
content(@user, :customizable_attributes) {
|
3630
|
+
@user.customizable_attributes.each do |attribute|
|
3631
|
+
entry {
|
3632
|
+
label attribute.to_s.split('_').map(&:capitalize).join(' ')
|
3633
|
+
text <=> [@user, attribute]
|
3634
|
+
}
|
3635
|
+
end
|
3636
|
+
}
|
3637
|
+
}
|
3638
|
+
```
|
3639
|
+
|
3640
|
+
The form above will only display fields for a model's customizable attributes, so if they change, the form content will change too. Learn more at the [Dynamic Form](/docs/examples/GLIMMER-DSL-LIBUI-ADVANCED-EXAMPLES.md#dynamic-form) example.
|
3641
|
+
|
3577
3642
|
#### Data-Binding API
|
3578
3643
|
|
3579
3644
|
To summarize the data-binding API:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.11.0
|
@@ -8,6 +8,7 @@
|
|
8
8
|
- [CPU Percentage](#cpu-percentage)
|
9
9
|
- [Custom Draw Text](#custom-draw-text)
|
10
10
|
- [Dynamic Area](#dynamic-area)
|
11
|
+
- [Dynamic Form](#dynamic-form)
|
11
12
|
- [Editable Column Table](#editable-column-table)
|
12
13
|
- [Editable Table](#editable-table)
|
13
14
|
- [Form Table](#form-table)
|
@@ -211,6 +212,33 @@ Version 4 (declarative stable `path` approach without [data-binding](#data-bindi
|
|
211
212
|
|
212
213
|
[examples/dynamic_area4.rb](/examples/dynamic_area4.rb)
|
213
214
|
|
215
|
+
|
216
|
+
## Dynamic Form
|
217
|
+
|
218
|
+
[examples/dynamic_form.rb](/examples/dynamic_form.rb)
|
219
|
+
|
220
|
+
Run with this command from the root of the project if you cloned the project:
|
221
|
+
|
222
|
+
```
|
223
|
+
ruby -r './lib/glimmer-dsl-libui' examples/dynamic_form.rb
|
224
|
+
```
|
225
|
+
|
226
|
+
Run with this command if you installed the [Ruby gem](https://rubygems.org/gems/glimmer-dsl-libui):
|
227
|
+
|
228
|
+
```
|
229
|
+
ruby -r glimmer-dsl-libui -e "require 'examples/dynamic_form'"
|
230
|
+
```
|
231
|
+
|
232
|
+

|
233
|
+
|
234
|
+

|
235
|
+
|
236
|
+

|
237
|
+
|
238
|
+

|
239
|
+
|
240
|
+

|
241
|
+
|
214
242
|
## Editable Column Table
|
215
243
|
|
216
244
|
[examples/editable_column_table.rb](/examples/editable_column_table.rb)
|
data/examples/button_counter.rb
CHANGED
@@ -1,28 +1,35 @@
|
|
1
1
|
require 'glimmer-dsl-libui'
|
2
2
|
|
3
|
-
class
|
4
|
-
include Glimmer
|
5
|
-
|
3
|
+
class Counter
|
6
4
|
attr_accessor :count
|
7
|
-
|
5
|
+
|
8
6
|
def initialize
|
9
7
|
self.count = 0
|
10
8
|
end
|
9
|
+
end
|
11
10
|
|
12
|
-
|
11
|
+
class ButtonCounter
|
12
|
+
include Glimmer::LibUI::Application
|
13
|
+
|
14
|
+
before_body do
|
15
|
+
@counter = Counter.new
|
16
|
+
end
|
17
|
+
|
18
|
+
body {
|
13
19
|
window('Hello, Button!', 190, 20) {
|
14
20
|
vertical_box {
|
15
21
|
button {
|
16
|
-
# data-bind button text to
|
17
|
-
text <= [
|
22
|
+
# data-bind button text to @counter count, converting to string on read from model.
|
23
|
+
text <= [@counter, :count, on_read: ->(count) {"Count: #{count}"}]
|
18
24
|
|
19
25
|
on_clicked do
|
20
|
-
|
26
|
+
# This change will automatically propagate to button text through data-binding above
|
27
|
+
@counter.count += 1
|
21
28
|
end
|
22
29
|
}
|
23
30
|
}
|
24
|
-
}
|
25
|
-
|
31
|
+
}
|
32
|
+
}
|
26
33
|
end
|
27
34
|
|
28
|
-
ButtonCounter.
|
35
|
+
ButtonCounter.launch
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
|
3
|
+
class User
|
4
|
+
ALL_ATTRIBUTES = [:first_name, :last_name, :email, :street, :city, :state, :zip_code, :country]
|
5
|
+
|
6
|
+
attr_accessor :customizable_attributes, *ALL_ATTRIBUTES
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
# allow customizing all attributes by default
|
10
|
+
self.customizable_attributes = ALL_ATTRIBUTES.dup
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class DynamicForm
|
15
|
+
include Glimmer::LibUI::Application
|
16
|
+
|
17
|
+
before_body do
|
18
|
+
@user = User.new
|
19
|
+
end
|
20
|
+
|
21
|
+
body {
|
22
|
+
window('Dynamic Form') {
|
23
|
+
margined true
|
24
|
+
|
25
|
+
vertical_box {
|
26
|
+
horizontal_box {
|
27
|
+
User::ALL_ATTRIBUTES.each do |attribute|
|
28
|
+
checkbox(attribute.to_s) {
|
29
|
+
checked <=> [@user, :customizable_attributes,
|
30
|
+
on_read: -> (attributes) { @user.customizable_attributes.include?(attribute) },
|
31
|
+
on_write: -> (checked_value) {
|
32
|
+
if checked_value
|
33
|
+
@user.customizable_attributes.push(attribute)
|
34
|
+
else
|
35
|
+
@user.customizable_attributes.delete(attribute)
|
36
|
+
end
|
37
|
+
@user.customizable_attributes.sort_by {|attribute| User::ALL_ATTRIBUTES.index(attribute)}
|
38
|
+
},
|
39
|
+
]
|
40
|
+
}
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
form {
|
45
|
+
stretchy false
|
46
|
+
|
47
|
+
# Control content data-binding allows dynamically changing content based on changes in a model attribute
|
48
|
+
content(@user, :customizable_attributes) {
|
49
|
+
@user.customizable_attributes.each do |attribute|
|
50
|
+
entry {
|
51
|
+
label attribute.to_s.split('_').map(&:capitalize).join(' ')
|
52
|
+
text <=> [@user, attribute]
|
53
|
+
}
|
54
|
+
end
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
button('Summarize') {
|
59
|
+
on_clicked do
|
60
|
+
summary = @user.customizable_attributes.map { |attribute| @user.send(attribute) }.join(', ')
|
61
|
+
msg_box('Summary', summary)
|
62
|
+
end
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
DynamicForm.launch
|
@@ -47,10 +47,33 @@ class Snake
|
|
47
47
|
self.joins.clear
|
48
48
|
end
|
49
49
|
|
50
|
+
def turn_right
|
51
|
+
head.orientation = RIGHT_TURN_MAP[head.orientation]
|
52
|
+
end
|
53
|
+
|
54
|
+
def turn_left
|
55
|
+
head.orientation = LEFT_TURN_MAP[head.orientation]
|
56
|
+
end
|
57
|
+
|
50
58
|
def move
|
51
|
-
|
59
|
+
create_new_head
|
60
|
+
remove_old_tail
|
61
|
+
if detect_collision?
|
62
|
+
collide_and_die
|
63
|
+
else
|
64
|
+
append_new_head
|
65
|
+
eat_apple if detect_apple?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def remove_old_tail
|
70
|
+
@old_tail = tail.dup # save in case of growing and keeping old tail
|
71
|
+
@vertebrae.delete(tail)
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_new_head
|
52
75
|
@new_head = head.dup
|
53
|
-
case
|
76
|
+
case head.orientation
|
54
77
|
when :east
|
55
78
|
@new_head.column = (@new_head.column + 1) % @game.width
|
56
79
|
when :west
|
@@ -60,25 +83,28 @@ class Snake
|
|
60
83
|
when :north
|
61
84
|
@new_head.row = (@new_head.row - 1) % @game.height
|
62
85
|
end
|
63
|
-
if @vertebrae.map {|v| [v.row, v.column]}.include?([@new_head.row, @new_head.column])
|
64
|
-
self.collided = true
|
65
|
-
@game.over = true
|
66
|
-
else
|
67
|
-
@vertebrae.append(@new_head)
|
68
|
-
@vertebrae.delete(tail)
|
69
|
-
if head.row == @game.apple.row && head.column == @game.apple.column
|
70
|
-
grow
|
71
|
-
@game.apple.generate
|
72
|
-
end
|
73
|
-
end
|
74
86
|
end
|
75
87
|
|
76
|
-
def
|
77
|
-
|
88
|
+
def append_new_head
|
89
|
+
@vertebrae.append(@new_head)
|
78
90
|
end
|
79
91
|
|
80
|
-
def
|
81
|
-
|
92
|
+
def detect_collision?
|
93
|
+
@vertebrae.map {|v| [v.row, v.column]}.include?([@new_head.row, @new_head.column])
|
94
|
+
end
|
95
|
+
|
96
|
+
def collide_and_die
|
97
|
+
self.collided = true
|
98
|
+
@game.over = true
|
99
|
+
end
|
100
|
+
|
101
|
+
def detect_apple?
|
102
|
+
head.row == @game.apple.row && head.column == @game.apple.column
|
103
|
+
end
|
104
|
+
|
105
|
+
def eat_apple
|
106
|
+
grow
|
107
|
+
@game.apple.generate
|
82
108
|
end
|
83
109
|
|
84
110
|
def grow
|
data/examples/snake.rb
CHANGED
@@ -72,12 +72,16 @@ class Snake
|
|
72
72
|
fill <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
|
73
73
|
}
|
74
74
|
|
75
|
-
|
75
|
+
on_key_down do |area_key_event|
|
76
|
+
handled = true # assume we will handle the event
|
76
77
|
if area_key_event[:key] == ' '
|
77
78
|
@game.toggle_pause
|
78
|
-
|
79
|
+
elsif %i[up right down left].include?(area_key_event[:ext_key])
|
79
80
|
@keypress_queue << area_key_event[:ext_key]
|
81
|
+
else
|
82
|
+
handled = false # we won't handle the event after all
|
80
83
|
end
|
84
|
+
handled
|
81
85
|
end
|
82
86
|
}
|
83
87
|
end
|
data/glimmer-dsl-libui.gemspec
CHANGED
Binary file
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright (c) 2021-2023 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/dsl/static_expression'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module DSL
|
26
|
+
module Libui
|
27
|
+
class ContentExpression < StaticExpression
|
28
|
+
def can_interpret?(parent, keyword, *args, &block)
|
29
|
+
keyword == 'content' &&
|
30
|
+
block_given? &&
|
31
|
+
args.size > 0 &&
|
32
|
+
parent&.respond_to?(:bind_content)
|
33
|
+
end
|
34
|
+
|
35
|
+
def interpret(parent, keyword, *args, &block)
|
36
|
+
parent.bind_content(*args, &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -384,6 +384,19 @@ module Glimmer
|
|
384
384
|
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Libui::ControlExpression.new, @keyword, {post_add_content: @content_added}, &block)
|
385
385
|
end
|
386
386
|
|
387
|
+
# Data-binds the generation of nested content to a model/property (in binding args)
|
388
|
+
# consider providing an option to avoid initial rendering without any changes happening
|
389
|
+
def bind_content(*binding_args, &content_block)
|
390
|
+
# TODO in the future, consider optimizing code by diffing content if that makes sense
|
391
|
+
content_binding_work = proc do |*values|
|
392
|
+
children.dup.each { |child| child.destroy }
|
393
|
+
content(&content_block)
|
394
|
+
end
|
395
|
+
content_binding_observer = Glimmer::DataBinding::Observer.proc(&content_binding_work)
|
396
|
+
content_binding_observer.observe(*binding_args)
|
397
|
+
content_binding_work.call # TODO inspect if we need to pass args here (from observed attributes) [but it's simpler not to pass anything at first]
|
398
|
+
end
|
399
|
+
|
387
400
|
private
|
388
401
|
|
389
402
|
def build_control
|
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.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -437,6 +437,7 @@ files:
|
|
437
437
|
- examples/dynamic_area2.rb
|
438
438
|
- examples/dynamic_area3.rb
|
439
439
|
- examples/dynamic_area4.rb
|
440
|
+
- examples/dynamic_form.rb
|
440
441
|
- examples/editable_column_table.rb
|
441
442
|
- examples/editable_table.rb
|
442
443
|
- examples/font_button.rb
|
@@ -500,6 +501,7 @@ files:
|
|
500
501
|
- lib/glimmer-dsl-libui/ext/rouge/theme/glimmer.rb
|
501
502
|
- lib/glimmer/Rakefile
|
502
503
|
- lib/glimmer/dsl/libui/bind_expression.rb
|
504
|
+
- lib/glimmer/dsl/libui/content_expression.rb
|
503
505
|
- lib/glimmer/dsl/libui/control_expression.rb
|
504
506
|
- lib/glimmer/dsl/libui/custom_control_expression.rb
|
505
507
|
- lib/glimmer/dsl/libui/custom_shape_expression.rb
|