glimmer-dsl-libui 0.3.4 → 0.4.2

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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.4
1
+ 0.4.2
@@ -4,6 +4,21 @@ include Glimmer
4
4
 
5
5
  window('Area Gallery', 400, 400) {
6
6
  area {
7
+ path { # declarative stable path (explicit path syntax for multiple shapes sharing attributes)
8
+ square(0, 0, 100)
9
+ square(100, 100, 400)
10
+
11
+ fill r: 102, g: 102, b: 204
12
+ }
13
+
14
+ path { # declarative stable path (explicit path syntax for multiple shapes sharing attributes)
15
+ rectangle(0, 100, 100, 400)
16
+ rectangle(100, 0, 400, 100)
17
+
18
+ # linear gradient (has x0, y0, x1, y1, and stops)
19
+ fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
20
+ }
21
+
7
22
  polygon(100, 100, 100, 400, 400, 100, 400, 400) { # declarative stable path (implicit path syntax for a single shape nested directly under area)
8
23
  fill r: 202, g: 102, b: 104, a: 0.5
9
24
  stroke r: 0, g: 0, b: 0
@@ -32,21 +47,6 @@ window('Area Gallery', 400, 400) {
32
47
  stroke r: 0, g: 0, b: 0, thickness: 2
33
48
  }
34
49
 
35
- path { # declarative stable path (explicit path syntax for multiple shapes sharing attributes)
36
- square(0, 0, 100)
37
- square(100, 100, 400)
38
-
39
- fill r: 102, g: 102, b: 204
40
- }
41
-
42
- path { # declarative stable path (explicit path syntax for multiple shapes sharing attributes)
43
- rectangle(0, 100, 100, 400)
44
- rectangle(100, 0, 400, 100)
45
-
46
- # linear gradient (has x0, y0, x1, y1, and stops)
47
- fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
48
- }
49
-
50
50
  text(161, 40, 100) { # declarative stable text
51
51
  string('Area Gallery') {
52
52
  font family: 'Arial', size: (OS.mac? ? 14 : 11)
@@ -4,7 +4,41 @@ include Glimmer
4
4
 
5
5
  window('Area Gallery', 400, 400) {
6
6
  area {
7
-
7
+ path { # declarative stable path with explicit attributes (explicit path syntax for multiple shapes sharing attributes)
8
+ square {
9
+ x 0
10
+ y 0
11
+ length 100
12
+ }
13
+
14
+ square {
15
+ x 100
16
+ y 100
17
+ length 400
18
+ }
19
+
20
+ fill r: 102, g: 102, b: 204
21
+ }
22
+
23
+ path { # declarative stable path with explicit attributes (explicit path syntax for multiple shapes sharing attributes)
24
+ rectangle {
25
+ x 0
26
+ y 100
27
+ width 100
28
+ height 400
29
+ }
30
+
31
+ rectangle {
32
+ x 100
33
+ y 0
34
+ width 400
35
+ height 100
36
+ }
37
+
38
+ # linear gradient (has x0, y0, x1, y1, and stops)
39
+ fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
40
+ }
41
+
8
42
  figure { # declarative stable path with explicit attributes (implicit path syntax for a single shape nested directly under area)
9
43
  x 100
10
44
  y 100
@@ -111,41 +145,6 @@ window('Area Gallery', 400, 400) {
111
145
  stroke r: 0, g: 0, b: 0, thickness: 2
112
146
  }
113
147
 
114
- path { # declarative stable path with explicit attributes (explicit path syntax for multiple shapes sharing attributes)
115
- square {
116
- x 0
117
- y 0
118
- length 100
119
- }
120
-
121
- square {
122
- x 100
123
- y 100
124
- length 400
125
- }
126
-
127
- fill r: 102, g: 102, b: 204
128
- }
129
-
130
- path { # declarative stable path with explicit attributes (explicit path syntax for multiple shapes sharing attributes)
131
- rectangle {
132
- x 0
133
- y 100
134
- width 100
135
- height 400
136
- }
137
-
138
- rectangle {
139
- x 100
140
- y 0
141
- width 400
142
- height 100
143
- }
144
-
145
- # linear gradient (has x0, y0, x1, y1, and stops)
146
- fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
147
- }
148
-
149
148
  text { # declarative stable text with explicit attributes
150
149
  x 161
151
150
  y 40
@@ -5,6 +5,21 @@ include Glimmer
5
5
  window('Area Gallery', 400, 400) {
6
6
  area {
7
7
  on_draw do |area_draw_params|
8
+ path { # dynamic path, added semi-declaratively inside on_draw block
9
+ square(0, 0, 100)
10
+ square(100, 100, 400)
11
+
12
+ fill r: 102, g: 102, b: 204
13
+ }
14
+
15
+ path { # dynamic path, added semi-declaratively inside on_draw block
16
+ rectangle(0, 100, 100, 400)
17
+ rectangle(100, 0, 400, 100)
18
+
19
+ # linear gradient (has x0, y0, x1, y1, and stops)
20
+ fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
21
+ }
22
+
8
23
  polygon(100, 100, 100, 400, 400, 100, 400, 400) { # dynamic path, added semi-declaratively inside on_draw block
9
24
  fill r: 202, g: 102, b: 104, a: 0.5
10
25
  stroke r: 0, g: 0, b: 0
@@ -33,21 +48,6 @@ window('Area Gallery', 400, 400) {
33
48
  stroke r: 0, g: 0, b: 0, thickness: 2
34
49
  }
35
50
 
36
- path { # dynamic path, added semi-declaratively inside on_draw block
37
- square(0, 0, 100)
38
- square(100, 100, 400)
39
-
40
- fill r: 102, g: 102, b: 204
41
- }
42
-
43
- path { # dynamic path, added semi-declaratively inside on_draw block
44
- rectangle(0, 100, 100, 400)
45
- rectangle(100, 0, 400, 100)
46
-
47
- # linear gradient (has x0, y0, x1, y1, and stops)
48
- fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
49
- }
50
-
51
51
  text(161, 40, 100) { # dynamic text added semi-declaratively inside on_draw block
52
52
  string('Area Gallery') {
53
53
  font family: 'Arial', size: (OS.mac? ? 14 : 11)
@@ -5,6 +5,41 @@ include Glimmer
5
5
  window('Area Gallery', 400, 400) {
6
6
  area {
7
7
  on_draw do |area_draw_params|
8
+ path { # dynamic path, added semi-declaratively inside on_draw block
9
+ square {
10
+ x 0
11
+ y 0
12
+ length 100
13
+ }
14
+
15
+ square {
16
+ x 100
17
+ y 100
18
+ length 400
19
+ }
20
+
21
+ fill r: 102, g: 102, b: 204
22
+ }
23
+
24
+ path { # dynamic path, added semi-declaratively inside on_draw block
25
+ rectangle {
26
+ x 0
27
+ y 100
28
+ width 100
29
+ height 400
30
+ }
31
+
32
+ rectangle {
33
+ x 100
34
+ y 0
35
+ width 400
36
+ height 100
37
+ }
38
+
39
+ # linear gradient (has x0, y0, x1, y1, and stops)
40
+ fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
41
+ }
42
+
8
43
  figure { # dynamic path, added semi-declaratively inside on_draw block
9
44
  x 100
10
45
  y 100
@@ -111,41 +146,6 @@ window('Area Gallery', 400, 400) {
111
146
  stroke r: 0, g: 0, b: 0, thickness: 2
112
147
  }
113
148
 
114
- path { # dynamic path, added semi-declaratively inside on_draw block
115
- square {
116
- x 0
117
- y 0
118
- length 100
119
- }
120
-
121
- square {
122
- x 100
123
- y 100
124
- length 400
125
- }
126
-
127
- fill r: 102, g: 102, b: 204
128
- }
129
-
130
- path { # dynamic path, added semi-declaratively inside on_draw block
131
- rectangle {
132
- x 0
133
- y 100
134
- width 100
135
- height 400
136
- }
137
-
138
- rectangle {
139
- x 100
140
- y 0
141
- width 400
142
- height 100
143
- }
144
-
145
- # linear gradient (has x0, y0, x1, y1, and stops)
146
- fill x0: 10, y0: 10, x1: 350, y1: 350, stops: [{pos: 0.25, r: 204, g: 102, b: 204}, {pos: 0.75, r: 102, g: 102, b: 204}]
147
- }
148
-
149
149
  text { # dynamic path, added semi-declaratively inside on_draw block
150
150
  x 161
151
151
  y 40
@@ -0,0 +1,27 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class ButtonCounter
4
+ include Glimmer
5
+
6
+ attr_accessor :count
7
+
8
+ def initialize
9
+ @count = 0
10
+ end
11
+
12
+ def launch
13
+ window('Hello, Button!', 190, 20) {
14
+ vertical_box {
15
+ button {
16
+ text <= [self, :count, on_read: ->(count) {"Count: #{count}"}] # data-bind button text to self count, converting to string on read.
17
+
18
+ on_clicked do
19
+ self.count += 1
20
+ end
21
+ }
22
+ }
23
+ }.show
24
+ end
25
+ end
26
+
27
+ ButtonCounter.new.launch
@@ -26,7 +26,8 @@ class ColorTheCircles
26
26
  end
27
27
 
28
28
  def register_observers
29
- observer = Glimmer::DataBinding::Observer.proc do |new_score|
29
+ # observe automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer block of score attribute changes
30
+ observe(self, :score) do |new_score|
30
31
  Glimmer::LibUI.queue_main do
31
32
  @score_label.text = new_score.to_s
32
33
  if new_score == -20
@@ -40,7 +41,6 @@ class ColorTheCircles
40
41
  end
41
42
  end
42
43
  end
43
- observer.observe(self, :score) # automatically enhances self to become Glimmer::DataBinding::ObservableModel and notify observer on score attribute changes
44
44
  end
45
45
 
46
46
  def setup_circle_factory
@@ -40,7 +40,7 @@ class MetaExample
40
40
  end
41
41
 
42
42
  def version_count_for(example)
43
- Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/\d\.rb$/)}.count + 1
43
+ Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/#{example.underscore}\d\.rb$/)}.count + 1
44
44
  end
45
45
 
46
46
  def glimmer_dsl_libui_file
@@ -34,9 +34,9 @@ def label_pair(model, attribute, value)
34
34
  name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
35
35
  value_label = label(value.to_s)
36
36
  }
37
- Glimmer::DataBinding::Observer.proc do
37
+ observe(model, attribute) do
38
38
  value_label.text = model.send(attribute)
39
- end.observe(model, attribute)
39
+ end
40
40
  end
41
41
 
42
42
  def address(address)
@@ -18,12 +18,8 @@ class TinyMidiPlayer
18
18
 
19
19
  def stop_midi
20
20
  if @pid
21
- if @th.alive?
22
- Process.kill(:SIGKILL, @pid)
23
- @pid = nil
24
- else
25
- @pid = nil
26
- end
21
+ Process.kill(:SIGKILL, @pid) if @th.alive?
22
+ @pid = nil
27
23
  end
28
24
  end
29
25
 
@@ -6,8 +6,8 @@ require_relative 'apple'
6
6
  class Snake
7
7
  module Model
8
8
  class Game
9
- WIDTH_DEFAULT = 40
10
- HEIGHT_DEFAULT = 40
9
+ WIDTH_DEFAULT = 20
10
+ HEIGHT_DEFAULT = 20
11
11
  FILE_HIGH_SCORE = File.expand_path(File.join(Dir.home, '.glimmer-snake'))
12
12
 
13
13
  attr_reader :width, :height
@@ -1,10 +1,12 @@
1
- require 'glimmer/data_binding/observer'
1
+ require 'glimmer'
2
2
  require_relative '../model/game'
3
3
  require_relative 'cell'
4
4
 
5
5
  class Snake
6
6
  module Presenter
7
7
  class Grid
8
+ include Glimmer
9
+
8
10
  attr_reader :game, :cells
9
11
 
10
12
  def initialize(game = Model::Game.new)
@@ -14,7 +16,7 @@ class Snake
14
16
  Cell.new(grid: self, row: row, column: column)
15
17
  end
16
18
  end
17
- Glimmer::DataBinding::Observer.proc do |new_vertebrae|
19
+ observe(@game.snake, :vertebrae) do |new_vertebrae|
18
20
  occupied_snake_positions = @game.snake.vertebrae.map {|v| [v.row, v.column]}
19
21
  @cells.each_with_index do |row_cells, row|
20
22
  row_cells.each_with_index do |cell, column|
@@ -27,7 +29,7 @@ class Snake
27
29
  end
28
30
  end
29
31
  end
30
- end.observe(@game.snake, :vertebrae)
32
+ end
31
33
  end
32
34
 
33
35
  def clear
data/examples/snake.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  require 'glimmer-dsl-libui'
2
- require 'glimmer/data_binding/observer'
3
2
 
4
3
  require_relative 'snake/presenter/grid'
5
4
 
6
5
  class Snake
6
+ include Glimmer
7
+
7
8
  CELL_SIZE = 15
8
9
  SNAKE_MOVE_DELAY = 0.1
9
- include Glimmer
10
10
 
11
11
  def initialize
12
12
  @game = Model::Game.new
@@ -21,48 +21,38 @@ class Snake
21
21
  end
22
22
 
23
23
  def register_observers
24
- @game.height.times do |row|
25
- @game.width.times do |column|
26
- Glimmer::DataBinding::Observer.proc do |new_color|
27
- @cell_grid[row][column].fill = new_color
28
- end.observe(@grid.cells[row][column], :color)
29
- end
30
- end
31
-
32
- Glimmer::DataBinding::Observer.proc do |game_over|
24
+ observe(@game, :over) do |game_over|
33
25
  Glimmer::LibUI.queue_main do
34
26
  if game_over
35
27
  msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
36
28
  @game.start
37
29
  end
38
30
  end
39
- end.observe(@game, :over)
31
+ end
40
32
 
41
33
  Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
42
- unless @game.over?
43
- @game.snake.move
44
- @main_window.title = "Glimmer Snake (Score: #{@game.score} | High Score: #{@game.high_score})"
45
- end
34
+ @game.snake.move unless @game.over?
46
35
  end
47
36
  end
48
37
 
49
38
  def create_gui
50
- @cell_grid = []
51
- @main_window = window('Glimmer Snake', @game.width * CELL_SIZE, @game.height * CELL_SIZE) {
39
+ @main_window = window {
40
+ # data-bind window title to game score, converting it to a title string on read from the model
41
+ title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
42
+ content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
52
43
  resizable false
53
44
 
54
45
  vertical_box {
55
46
  padded false
56
47
 
57
48
  @game.height.times do |row|
58
- @cell_grid << []
59
49
  horizontal_box {
60
50
  padded false
61
51
 
62
52
  @game.width.times do |column|
63
53
  area {
64
- @cell_grid.last << square(0, 0, CELL_SIZE) {
65
- fill Presenter::Cell::COLOR_CLEAR
54
+ square(0, 0, CELL_SIZE) {
55
+ fill <= [@grid.cells[row][column], :color] # data-bind square fill to grid cell color
66
56
  }
67
57
 
68
58
  on_key_up do |area_key_event|
data/examples/tetris.rb CHANGED
@@ -42,7 +42,7 @@ class Tetris
42
42
  end
43
43
 
44
44
  def register_observers
45
- Glimmer::DataBinding::Observer.proc do |game_over|
45
+ observe(@game, :game_over) do |game_over|
46
46
  if game_over
47
47
  @pause_menu_item.enabled = false
48
48
  show_game_over_dialog
@@ -50,11 +50,11 @@ class Tetris
50
50
  @pause_menu_item.enabled = true
51
51
  start_moving_tetrominos_down
52
52
  end
53
- end.observe(@game, :game_over)
53
+ end
54
54
 
55
55
  Model::Game::PLAYFIELD_HEIGHT.times do |row|
56
56
  Model::Game::PLAYFIELD_WIDTH.times do |column|
57
- Glimmer::DataBinding::Observer.proc do |new_color|
57
+ observe(@game.playfield[row][column], :color) do |new_color|
58
58
  Glimmer::LibUI.queue_main do
59
59
  color = Glimmer::LibUI.interpret_color(new_color)
60
60
  block = @playfield_blocks[row][column]
@@ -65,13 +65,13 @@ class Tetris
65
65
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
66
66
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
67
67
  end
68
- end.observe(@game.playfield[row][column], :color)
68
+ end
69
69
  end
70
70
  end
71
71
 
72
72
  Model::Game::PREVIEW_PLAYFIELD_HEIGHT.times do |row|
73
73
  Model::Game::PREVIEW_PLAYFIELD_WIDTH.times do |column|
74
- Glimmer::DataBinding::Observer.proc do |new_color|
74
+ observe(@game.preview_playfield[row][column], :color) do |new_color|
75
75
  Glimmer::LibUI.queue_main do
76
76
  color = Glimmer::LibUI.interpret_color(new_color)
77
77
  block = @preview_playfield_blocks[row][column]
@@ -82,27 +82,27 @@ class Tetris
82
82
  block[:left_bevel_edge].fill = {r: color[:r] - BEVEL_CONSTANT, g: color[:g] - BEVEL_CONSTANT, b: color[:b] - BEVEL_CONSTANT}
83
83
  block[:border_square].stroke = new_color == Model::Block::COLOR_CLEAR ? COLOR_GRAY : color
84
84
  end
85
- end.observe(@game.preview_playfield[row][column], :color)
85
+ end
86
86
  end
87
87
  end
88
88
 
89
- Glimmer::DataBinding::Observer.proc do |new_score|
89
+ observe(@game, :score) do |new_score|
90
90
  Glimmer::LibUI.queue_main do
91
91
  @score_label.text = new_score.to_s
92
92
  end
93
- end.observe(@game, :score)
93
+ end
94
94
 
95
- Glimmer::DataBinding::Observer.proc do |new_lines|
95
+ observe(@game, :lines) do |new_lines|
96
96
  Glimmer::LibUI.queue_main do
97
97
  @lines_label.text = new_lines.to_s
98
98
  end
99
- end.observe(@game, :lines)
99
+ end
100
100
 
101
- Glimmer::DataBinding::Observer.proc do |new_level|
101
+ observe(@game, :level) do |new_level|
102
102
  Glimmer::LibUI.queue_main do
103
103
  @level_label.text = new_level.to_s
104
104
  end
105
- end.observe(@game, :level)
105
+ end
106
106
  end
107
107
 
108
108
  def menu_bar
@@ -16,17 +16,9 @@ class TicTacToe
16
16
  end
17
17
 
18
18
  def register_observers
19
- Glimmer::DataBinding::Observer.proc do |game_status|
19
+ observe(@tic_tac_toe_board, :game_status) do |game_status|
20
20
  display_win_message if game_status == Board::WIN
21
21
  display_draw_message if game_status == Board::DRAW
22
- end.observe(@tic_tac_toe_board, :game_status)
23
-
24
- 3.times.map do |row|
25
- 3.times.map do |column|
26
- Glimmer::DataBinding::Observer.proc do |sign|
27
- @cells[row][column].string = sign
28
- end.observe(@tic_tac_toe_board[row + 1, column + 1], :sign) # board model is 1-based
29
- end
30
22
  end
31
23
  end
32
24
 
@@ -34,12 +26,10 @@ class TicTacToe
34
26
  @main_window = window('Tic-Tac-Toe', 180, 180) {
35
27
  resizable false
36
28
 
37
- @cells = []
38
29
  vertical_box {
39
30
  padded false
40
31
 
41
32
  3.times.map do |row|
42
- @cells << []
43
33
  horizontal_box {
44
34
  padded false
45
35
 
@@ -49,8 +39,9 @@ class TicTacToe
49
39
  stroke :black, thickness: 2
50
40
  }
51
41
  text(23, 19) {
52
- @cells[row] << string('') {
42
+ string {
53
43
  font family: 'Arial', size: OS.mac? ? 20 : 16
44
+ string <= [@tic_tac_toe_board[row + 1, column + 1], :sign] # board model is 1-based
54
45
  }
55
46
  }
56
47
  on_mouse_up do
data/examples/timer.rb CHANGED
@@ -19,12 +19,8 @@ class Timer
19
19
 
20
20
  def stop_alarm
21
21
  if @pid
22
- if @th.alive?
23
- Process.kill(:SIGKILL, @pid)
24
- @pid = nil
25
- else
26
- @pid = nil
27
- end
22
+ Process.kill(:SIGKILL, @pid) if @th.alive?
23
+ @pid = nil
28
24
  end
29
25
  end
30
26
 
Binary file
@@ -0,0 +1,36 @@
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/dsl/static_expression'
23
+ require 'glimmer/dsl/bind_expression'
24
+
25
+ module Glimmer
26
+ module DSL
27
+ module Libui
28
+ # Responsible for setting up the return value of the bind keyword (command symbol)
29
+ # as a ModelBinding. It is then used by another command handler like
30
+ # DataBindingExpression
31
+ class BindExpression < StaticExpression
32
+ include Glimmer::DSL::BindExpression
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
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/dsl/expression'
23
+ require 'glimmer/data_binding/model_binding'
24
+
25
+ module Glimmer
26
+ module DSL
27
+ module Libui
28
+ # Responsible for wiring data-binding
29
+ # Depends on BindExpression
30
+ class DataBindingExpression < Expression
31
+ def can_interpret?(parent, keyword, *args, &block)
32
+ args.size == 1 and
33
+ args[0].is_a?(DataBinding::ModelBinding)
34
+ end
35
+
36
+ def interpret(parent, keyword, *args, &block)
37
+ model_binding = args[0]
38
+ model_attribute_observer = Glimmer::DataBinding::Observer.proc do
39
+ parent.send("#{keyword}=", model_binding.evaluate_property)
40
+ end
41
+ model_attribute_observer.observe(model_binding)
42
+ model_attribute_observer.call # initial update
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end