glimmer-dsl-libui 0.3.4 → 0.4.2

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