glimmer-dsl-libui 0.4.8 → 0.4.9

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: 122c9e87c9613b6ebb29722c0c7d602b0850f369c613374b21df38699e61e669
4
- data.tar.gz: fb156f42398d2c8d419de476dfe435fbdfe872545da343daadd035ed2667775c
3
+ metadata.gz: 755dfde419aa3c77d0ca7229f9962d63b7aa139adbc1d5543e93acbf0c1917db
4
+ data.tar.gz: f4d753f109947eafeea727804ee871923948a0a262cde11a58dfd2f2fbe893ec
5
5
  SHA512:
6
- metadata.gz: 0d9587a6a19b25436fb8b810034d4663d2bd6e6dd478ab7397727978b5cec3100016032a0b3b9787ffcdb7245c2df4826829fa3e0d0afd60b69a26f4e45fcdcd
7
- data.tar.gz: 8793a26d3383e981db6654b2e5e2705e677436e89eb1f678ec8289d17328d825151cb06ab67eacd19a398092ef77bafc6baa3e729c5152df57cf73189d9ad40e
6
+ metadata.gz: 96f4f5b7ddbf09a9543cea439ce74b1c5c545e2e6c240533e4d283ffba2bea16778a826601e2350392253d39edd21c8a6cb60d22fa1ee4107084c2cdd9155f70
7
+ data.tar.gz: 65b9fdb359801bdd1e4c6e9df74f3cc1d49f7012a5fc6b7dfc8cb4f6fbc16732cc6e4119a05d6c0a26eb559d60e3c72b263b3376f0775d4ff1ff5dd3ec52435d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.4.9
4
+
5
+ - Support unidirectional data-binding on all control properties that support bidirectional data-binding
6
+ - Fix issue in examples/snake.rb with double-turn causing instant death due to snake illogically going back against itself
7
+
3
8
  ## 0.4.8
4
9
 
5
10
  - Support `checkbox` `checked` bidirectional data-binding (with `<=>` sign)
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.4.8
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.4.9
2
2
  ## Prerequisite-Free Ruby Desktop Development GUI Library
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-libui.svg)](http://badge.fury.io/rb/glimmer-dsl-libui)
4
4
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
@@ -373,7 +373,7 @@ gem install glimmer-dsl-libui
373
373
  Or install via Bundler `Gemfile`:
374
374
 
375
375
  ```ruby
376
- gem 'glimmer-dsl-libui', '~> 0.4.8'
376
+ gem 'glimmer-dsl-libui', '~> 0.4.9'
377
377
  ```
378
378
 
379
379
  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.
@@ -1398,6 +1398,7 @@ Data-binding supports utilizing the [MVP (Model View Presenter)](https://en.wiki
1398
1398
  - `search_entry`: `text`
1399
1399
  - `slider`: `value`
1400
1400
  - `spinbox`: `value`
1401
+ - `table`: `cell_rows` (explicit data-binding using `<=>` and [implicit data-binding](#table-api) by assigning value directly)
1401
1402
  - `time_picker`: `time`
1402
1403
 
1403
1404
  Example of bidirectional data-binding:
@@ -3268,7 +3269,62 @@ Mac | Windows | Linux
3268
3269
  ----|---------|------
3269
3270
  ![glimmer-dsl-libui-mac-basic-table-button.png](images/glimmer-dsl-libui-mac-basic-table-button.png) ![glimmer-dsl-libui-mac-basic-table-button-deleted.png](images/glimmer-dsl-libui-mac-basic-table-button-deleted.png) | ![glimmer-dsl-libui-windows-basic-table-button.png](images/glimmer-dsl-libui-windows-basic-table-button.png) ![glimmer-dsl-libui-windows-basic-table-button-deleted.png](images/glimmer-dsl-libui-windows-basic-table-button-deleted.png) | ![glimmer-dsl-libui-linux-basic-table-button.png](images/glimmer-dsl-libui-linux-basic-table-button.png) ![glimmer-dsl-libui-linux-basic-table-button-deleted.png](images/glimmer-dsl-libui-linux-basic-table-button-deleted.png)
3270
3271
 
3271
- New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version:
3272
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version (with explicit [data-binding](#data-binding)):
3273
+
3274
+ ```ruby
3275
+ # frozen_string_literal: true
3276
+
3277
+ require 'glimmer-dsl-libui'
3278
+
3279
+ class BasicTableButton
3280
+ include Glimmer
3281
+
3282
+ attr_accessor :data
3283
+
3284
+ def initialize
3285
+ @data = [
3286
+ %w[cat meow delete],
3287
+ %w[dog woof delete],
3288
+ %w[chicken cock-a-doodle-doo delete],
3289
+ %w[horse neigh delete],
3290
+ %w[cow moo delete]
3291
+ ]
3292
+ end
3293
+
3294
+ def launch
3295
+ window('Animal sounds', 400, 200) {
3296
+ horizontal_box {
3297
+ table {
3298
+ text_column('Animal')
3299
+ text_column('Description')
3300
+ button_column('Action') {
3301
+ on_clicked do |row|
3302
+ # Option 1: direct data deletion is the simpler solution
3303
+ # @data.delete_at(row) # automatically deletes actual table row due to explicit data-binding
3304
+
3305
+ # Option 2: cloning only to demonstrate table row deletion upon explicit setting of data attribute (cloning is not recommended beyond demonstrating this point)
3306
+ new_data = @data.clone
3307
+ new_data.delete_at(row)
3308
+ self.data = new_data # automatically loses deleted table row due to explicit data-binding
3309
+ end
3310
+ }
3311
+
3312
+ cell_rows <=> [self, :data] # explicit data-binding of table cell_rows to self.data
3313
+
3314
+ on_changed do |row, type, row_data|
3315
+ puts "Row #{row} #{type}: #{row_data}"
3316
+ $stdout.flush
3317
+ end
3318
+ }
3319
+ }
3320
+ }.show
3321
+ end
3322
+ end
3323
+
3324
+ BasicTableButton.new.launch
3325
+ ```
3326
+
3327
+ New [Glimmer DSL for LibUI](https://rubygems.org/gems/glimmer-dsl-libui) Version 2 (with implicit [data-binding](#data-binding)):
3272
3328
 
3273
3329
  ```ruby
3274
3330
  require 'glimmer-dsl-libui'
@@ -6449,7 +6505,7 @@ require 'glimmer-dsl-libui'
6449
6505
  class FormTable
6450
6506
  include Glimmer
6451
6507
 
6452
- attr_accessor :name, :email, :phone, :city, :state, :filter_value
6508
+ attr_accessor :data, :name, :email, :phone, :city, :state, :filter_value
6453
6509
 
6454
6510
  def initialize
6455
6511
  @data = [
@@ -6520,10 +6576,10 @@ class FormTable
6520
6576
  after_write: ->(filter_value) { # execute after write to self.filter_value
6521
6577
  @unfiltered_data ||= @data.dup
6522
6578
  # Unfilter first to remove any previous filters
6523
- @data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
6579
+ self.data = @unfiltered_data # affects table indirectly through explicit data-binding
6524
6580
  # Now, apply filter if entered
6525
6581
  unless filter_value.empty?
6526
- @data.filter! do |row_data| # affects table indirectly through implicit data-binding
6582
+ self.data = @data.filter do |row_data| # affects table indirectly through explicit data-binding
6527
6583
  row_data.any? do |cell|
6528
6584
  cell.to_s.downcase.include?(filter_value.downcase)
6529
6585
  end
@@ -6540,7 +6596,7 @@ class FormTable
6540
6596
  text_column('City')
6541
6597
  text_column('State')
6542
6598
 
6543
- cell_rows @data # implicit data-binding
6599
+ cell_rows <=> [self, :data] # explicit data-binding
6544
6600
 
6545
6601
  on_changed do |row, type, row_data|
6546
6602
  puts "Row #{row} #{type}: #{row_data}"
@@ -8195,6 +8251,7 @@ class Snake
8195
8251
  @game = Model::Game.new
8196
8252
  @grid = Presenter::Grid.new(@game)
8197
8253
  @game.start
8254
+ @keypress_queue = []
8198
8255
  create_gui
8199
8256
  register_observers
8200
8257
  end
@@ -8214,14 +8271,30 @@ class Snake
8214
8271
  end
8215
8272
 
8216
8273
  Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
8217
- @game.snake.move unless @game.over?
8274
+ unless @game.over?
8275
+ process_queued_keypress
8276
+ @game.snake.move
8277
+ end
8278
+ end
8279
+ end
8280
+
8281
+ def process_queued_keypress
8282
+ # key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
8283
+ key = @keypress_queue.shift
8284
+ case [@game.snake.head.orientation, key]
8285
+ in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
8286
+ @game.snake.turn_right
8287
+ in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
8288
+ @game.snake.turn_left
8289
+ else
8290
+ # No Op
8218
8291
  end
8219
8292
  end
8220
8293
 
8221
8294
  def create_gui
8222
8295
  @main_window = window {
8223
8296
  # data-bind window title to game score, converting it to a title string on read from the model
8224
- title <= [@game, :score, on_read: -> (score) {"Glimmer Snake (Score: #{@game.score})"}]
8297
+ title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
8225
8298
  content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
8226
8299
  resizable false
8227
8300
 
@@ -8239,15 +8312,7 @@ class Snake
8239
8312
  }
8240
8313
 
8241
8314
  on_key_up do |area_key_event|
8242
- orientation_and_key = [@game.snake.head.orientation, area_key_event[:ext_key]]
8243
- case orientation_and_key
8244
- in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
8245
- @game.snake.turn_right
8246
- in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
8247
- @game.snake.turn_left
8248
- else
8249
- # No Op
8250
- end
8315
+ @keypress_queue << area_key_event[:ext_key]
8251
8316
  end
8252
8317
  }
8253
8318
  end
@@ -9115,7 +9180,7 @@ These features have been planned or suggested. You might see them in a future ve
9115
9180
  is fine, but please isolate to its own commit so I can cherry-pick
9116
9181
  around it.
9117
9182
 
9118
- Note that the latest development sometimes takes place in [development](https://github.com/AndyObtiva/glimmer-dsl-libui/tree/development) branch (which is deleted once merged back to [master](https://github.com/AndyObtiva/glimmer-dsl-libui)).
9183
+ Note that the latest development sometimes takes place in the [development](https://github.com/AndyObtiva/glimmer-dsl-libui/tree/development) branch (usually deleted once merged back to [master](https://github.com/AndyObtiva/glimmer-dsl-libui)).
9119
9184
 
9120
9185
  ## Contributors
9121
9186
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.8
1
+ 0.4.9
data/examples/snake.rb CHANGED
@@ -12,6 +12,7 @@ class Snake
12
12
  @game = Model::Game.new
13
13
  @grid = Presenter::Grid.new(@game)
14
14
  @game.start
15
+ @keypress_queue = []
15
16
  create_gui
16
17
  register_observers
17
18
  end
@@ -31,7 +32,23 @@ class Snake
31
32
  end
32
33
 
33
34
  Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
34
- @game.snake.move unless @game.over?
35
+ unless @game.over?
36
+ process_queued_keypress
37
+ @game.snake.move
38
+ end
39
+ end
40
+ end
41
+
42
+ def process_queued_keypress
43
+ # key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
44
+ key = @keypress_queue.shift
45
+ case [@game.snake.head.orientation, key]
46
+ in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
47
+ @game.snake.turn_right
48
+ in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
49
+ @game.snake.turn_left
50
+ else
51
+ # No Op
35
52
  end
36
53
  end
37
54
 
@@ -56,15 +73,7 @@ class Snake
56
73
  }
57
74
 
58
75
  on_key_up do |area_key_event|
59
- orientation_and_key = [@game.snake.head.orientation, area_key_event[:ext_key]]
60
- case orientation_and_key
61
- in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
62
- @game.snake.turn_right
63
- in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
64
- @game.snake.turn_left
65
- else
66
- # No Op
67
- end
76
+ @keypress_queue << area_key_event[:ext_key]
68
77
  end
69
78
  }
70
79
  end
Binary file
@@ -30,8 +30,7 @@ module Glimmer
30
30
  class CheckboxProxy < ControlProxy
31
31
  DEFAULT_TEXT = ''
32
32
 
33
- def data_bind(property, model_binding)
34
- super
33
+ def data_bind_write(property, model_binding)
35
34
  handle_listener('on_toggled') { model_binding.call(checked) } if property == 'checked'
36
35
  end
37
36
 
@@ -114,8 +114,7 @@ module Glimmer
114
114
  super
115
115
  end
116
116
 
117
- def data_bind(property, model_binding)
118
- super
117
+ def data_bind_write(property, model_binding)
119
118
  handle_listener('on_changed') { model_binding.call(color) } if property == 'color'
120
119
  end
121
120
  end
@@ -64,8 +64,7 @@ module Glimmer
64
64
  alias set_selected_item selected_item
65
65
  alias selected_item= selected_item
66
66
 
67
- def data_bind(property, model_binding)
68
- super # model to view data-binding
67
+ def data_bind_write(property, model_binding)
69
68
  case property
70
69
  when 'selected'
71
70
  handle_listener('on_selected') { model_binding.call(selected) }
@@ -65,8 +65,7 @@ module Glimmer
65
65
  super
66
66
  end
67
67
 
68
- def data_bind(property, model_binding)
69
- super
68
+ def data_bind_write(property, model_binding)
70
69
  handle_listener('on_changed') { model_binding.call(time) } if property == 'time'
71
70
  end
72
71
  end
@@ -40,8 +40,7 @@ module Glimmer
40
40
  alias set_items items
41
41
  alias items= items
42
42
 
43
- def data_bind(property, model_binding)
44
- super
43
+ def data_bind_write(property, model_binding)
45
44
  handle_listener('on_changed') { model_binding.call(text) } if property == 'text'
46
45
  end
47
46
  end
@@ -28,8 +28,7 @@ module Glimmer
28
28
  #
29
29
  # Follows the Proxy Design Pattern
30
30
  class EntryProxy < ControlProxy
31
- def data_bind(property, model_binding)
32
- super
31
+ def data_bind_write(property, model_binding)
33
32
  handle_listener('on_changed') { model_binding.call(text) } if property == 'text'
34
33
  end
35
34
 
@@ -65,7 +65,11 @@ module Glimmer
65
65
  super
66
66
  end
67
67
 
68
- def data_bind(property, model_binding)
68
+ def data_bind_read(property, model_binding)
69
+ # No Op
70
+ end
71
+
72
+ def data_bind_write(property, model_binding)
69
73
  handle_listener('on_changed') { model_binding.call(font) } if property == 'font'
70
74
  end
71
75
  end
@@ -29,8 +29,7 @@ module Glimmer
29
29
  #
30
30
  # Follows the Proxy Design Pattern
31
31
  class CheckMenuItemProxy < MenuItemProxy
32
- def data_bind(property, model_binding)
33
- super
32
+ def data_bind_write(property, model_binding)
34
33
  handle_listener('on_clicked') { model_binding.call(checked) } if property == 'checked'
35
34
  end
36
35
 
@@ -65,8 +65,7 @@ module Glimmer
65
65
  end
66
66
  end
67
67
 
68
- def data_bind(property, model_binding)
69
- super
68
+ def data_bind_write(property, model_binding)
70
69
  handle_listener('on_clicked') { model_binding.call(checked) } if property == 'checked'
71
70
  end
72
71
 
@@ -28,8 +28,7 @@ module Glimmer
28
28
  #
29
29
  # Follows the Proxy Design Pattern
30
30
  class MultilineEntryProxy < ControlProxy
31
- def data_bind(property, model_binding)
32
- super
31
+ def data_bind_write(property, model_binding)
33
32
  handle_listener('on_changed') { model_binding.call(text) } if property == 'text'
34
33
  end
35
34
 
@@ -50,8 +50,7 @@ module Glimmer
50
50
  alias set_selected_item selected_item
51
51
  alias selected_item= selected_item
52
52
 
53
- def data_bind(property, model_binding)
54
- super # model to view data-binding
53
+ def data_bind_write(property, model_binding)
55
54
  case property
56
55
  when 'selected'
57
56
  handle_listener('on_selected') { model_binding.call(selected) }
@@ -28,8 +28,7 @@ module Glimmer
28
28
  #
29
29
  # Follows the Proxy Design Pattern
30
30
  class SliderProxy < ControlProxy
31
- def data_bind(property, model_binding)
32
- super
31
+ def data_bind_write(property, model_binding)
33
32
  handle_listener('on_changed') { model_binding.call(value) } if property == 'value'
34
33
  end
35
34
  end
@@ -28,8 +28,7 @@ module Glimmer
28
28
  #
29
29
  # Follows the Proxy Design Pattern
30
30
  class SpinboxProxy < ControlProxy
31
- def data_bind(property, model_binding)
32
- super
31
+ def data_bind_write(property, model_binding)
33
32
  handle_listener('on_changed') { model_binding.call(value) } if property == 'value'
34
33
  end
35
34
  end
@@ -23,9 +23,25 @@ module Glimmer
23
23
  module LibUI
24
24
  # Parent controls and shapes who have children and add child post_initialize_child
25
25
  module DataBindable
26
- # Data-binds model to update view.
27
- # Subclasses can override to do inverse data-binding by observing view control for property changes and updating model binding accordingly
26
+ # Sets up read/write (bidirectional) data-binding
27
+ #
28
+ # classes are expected to implement `data_bind_write(property, model_binding)` to setup write data-binding
29
+ # by observing view property for changes and writing to model attribute via model binding accordingly
30
+ #
31
+ # classes can override data_bind_read to disable read data-binding in rare scenarios that might need it
32
+ #
33
+ # returns model attribute reading observer by default
28
34
  def data_bind(property, model_binding)
35
+ data_bind_read(property, model_binding).tap do
36
+ data_bind_write(property, model_binding) unless model_binding.binding_options[:read_only]
37
+ end
38
+ end
39
+
40
+ # Sets up read data-binding (reading from model to update view)
41
+ #
42
+ # Default implementation observes model attribute for changes via model binding
43
+ # and updates view property accordingly
44
+ def data_bind_read(property, model_binding)
29
45
  model_attribute_observer = Glimmer::DataBinding::Observer.proc do
30
46
  new_value = model_binding.evaluate_property
31
47
  send("#{property}=", new_value) unless send(property) == new_value
@@ -34,6 +50,15 @@ module Glimmer
34
50
  model_attribute_observer.call # initial update
35
51
  model_attribute_observer
36
52
  end
53
+
54
+ # Sets up write data-binding (writing to model from view)
55
+ #
56
+ # Has no implementation by default. Classes are expected
57
+ # to implement this method by observing view property
58
+ # for changes and writing them to model accordingly via model binding
59
+ def data_bind_write(property, model_binding)
60
+ # No Op by default
61
+ end
37
62
  end
38
63
  end
39
64
  end
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.8
4
+ version: 0.4.9
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-11-29 00:00:00.000000000 Z
11
+ date: 2021-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer