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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21db2452d3dfbb5c34356de87e7c40380d4e887a25181854321a226cee7640b5
4
- data.tar.gz: 5f62aa411e6c890e0c8228d286f273d4ebb056af7b771313a49db0344340a773
3
+ metadata.gz: effb65102f9db3aa2977bac55edd4f67f91f1eafdae26403b8c044c714048a03
4
+ data.tar.gz: 3923d80a19afd62a0220026f33720ee953ad166880e17d60883aed53f9977d86
5
5
  SHA512:
6
- metadata.gz: fabf5fd00b7994fce070e6c200814381c3fbc7df0c38e7742e5d1207d76f0c0e9d1946d5b882ee5c372acd7cc6876e485596d760127a52ada556e6402de2dd31
7
- data.tar.gz: 37f4312b11de8d5f2678c2f31e966acfed33617224fcdd4217effdd169bcfd61721b1d1ff64236a4e0957d991f86127fc6c0db55170b3e0b92d5831c5cbc51ec
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, describing composite shapes/text/image concepts inside an `area`
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.10.1
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
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](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.10.1'
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
- Require [glimmer-dsl-libui](https://rubygems.org/gems/glimmer-dsl-libui) (whether through a Ruby `require` statement or `Bundler`) and then include the `Glimmer` or `Glimmer::LibUI::Application` module to enable access to the Glimmer GUI DSL in one of multiple approaches.
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 <=> [self, :entered_text, after_write: ->(text) {puts 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 `self` to `entry` `text` property and printing text after write to the model.
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.10.1
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
+ ![glimmer-dsl-libui-mac-dynamic-form.png](/images/glimmer-dsl-libui-mac-dynamic-form.png)
233
+
234
+ ![glimmer-dsl-libui-mac-dynamic-form-filled.png](/images/glimmer-dsl-libui-mac-dynamic-form-filled.png)
235
+
236
+ ![glimmer-dsl-libui-mac-dynamic-form-summarized.png](/images/glimmer-dsl-libui-mac-dynamic-form-summarized.png)
237
+
238
+ ![glimmer-dsl-libui-mac-dynamic-form-without-some-fields.png](/images/glimmer-dsl-libui-mac-dynamic-form-without-some-fields.png)
239
+
240
+ ![glimmer-dsl-libui-mac-dynamic-form-without-some-fields-summarized.png](/images/glimmer-dsl-libui-mac-dynamic-form-without-some-fields-summarized.png)
241
+
214
242
  ## Editable Column Table
215
243
 
216
244
  [examples/editable_column_table.rb](/examples/editable_column_table.rb)
@@ -1,28 +1,35 @@
1
1
  require 'glimmer-dsl-libui'
2
2
 
3
- class ButtonCounter
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
- def launch
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 self count, converting to string on read.
17
- text <= [self, :count, on_read: ->(count) {"Count: #{count}"}]
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
- self.count += 1
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
- }.show
25
- end
31
+ }
32
+ }
26
33
  end
27
34
 
28
- ButtonCounter.new.launch
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
- @old_tail = tail.dup
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 @new_head.orientation
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 turn_right
77
- head.orientation = RIGHT_TURN_MAP[head.orientation]
88
+ def append_new_head
89
+ @vertebrae.append(@new_head)
78
90
  end
79
91
 
80
- def turn_left
81
- head.orientation = LEFT_TURN_MAP[head.orientation]
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
- on_key_up do |area_key_event|
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
- else
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
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
@@ -40,6 +40,7 @@ module Glimmer
40
40
  data_binding
41
41
  shine_data_binding
42
42
  property
43
+ content
43
44
  string
44
45
  operation
45
46
  control
@@ -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.10.1
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-10-27 00:00:00.000000000 Z
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