glimmer-dsl-libui 0.4.8 → 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
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