glimmer-dsl-libui 0.4.1 → 0.4.5

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -1
  3. data/README.md +1628 -204
  4. data/VERSION +1 -1
  5. data/examples/basic_entry.rb +27 -24
  6. data/examples/basic_entry2.rb +31 -0
  7. data/examples/button_counter.rb +27 -0
  8. data/examples/dynamic_area.rb +77 -90
  9. data/examples/dynamic_area2.rb +14 -12
  10. data/examples/dynamic_area3.rb +90 -0
  11. data/examples/dynamic_area4.rb +95 -0
  12. data/examples/form.rb +42 -30
  13. data/examples/form2.rb +37 -0
  14. data/examples/form_table.rb +100 -87
  15. data/examples/form_table2.rb +93 -0
  16. data/examples/histogram.rb +98 -91
  17. data/examples/histogram2.rb +109 -0
  18. data/examples/login.rb +45 -39
  19. data/examples/login2.rb +55 -0
  20. data/examples/login3.rb +65 -0
  21. data/examples/login4.rb +61 -0
  22. data/examples/login5.rb +43 -0
  23. data/examples/meta_example.rb +10 -7
  24. data/examples/method_based_custom_keyword.rb +8 -15
  25. data/examples/method_based_custom_keyword2.rb +97 -0
  26. data/examples/snake.rb +1 -1
  27. data/examples/timer.rb +28 -31
  28. data/examples/timer2.rb +129 -0
  29. data/glimmer-dsl-libui.gemspec +0 -0
  30. data/lib/glimmer/dsl/libui/data_binding_expression.rb +4 -6
  31. data/lib/glimmer/libui/attributed_string.rb +3 -0
  32. data/lib/glimmer/libui/control_proxy/area_proxy.rb +52 -46
  33. data/lib/glimmer/libui/control_proxy/entry_proxy.rb +5 -0
  34. data/lib/glimmer/libui/control_proxy/image_proxy.rb +4 -5
  35. data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +5 -0
  36. data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +38 -0
  37. data/lib/glimmer/libui/control_proxy/table_proxy.rb +1 -1
  38. data/lib/glimmer/libui/control_proxy.rb +8 -1
  39. data/lib/glimmer/libui/data_bindable.rb +39 -0
  40. data/lib/glimmer/libui/shape.rb +7 -2
  41. metadata +17 -2
@@ -30,16 +30,14 @@ module Glimmer
30
30
  class DataBindingExpression < Expression
31
31
  def can_interpret?(parent, keyword, *args, &block)
32
32
  args.size == 1 and
33
- args[0].is_a?(DataBinding::ModelBinding)
33
+ args[0].is_a?(DataBinding::ModelBinding) and
34
+ parent.respond_to?(:data_bind)
34
35
  end
35
36
 
36
37
  def interpret(parent, keyword, *args, &block)
38
+ property = keyword
37
39
  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
40
+ parent.data_bind(property, model_binding)
43
41
  end
44
42
  end
45
43
  end
@@ -23,10 +23,13 @@ require 'glimmer/libui/control_proxy'
23
23
  require 'glimmer/libui/control_proxy/area_proxy'
24
24
  require 'glimmer/libui/parent'
25
25
  require 'glimmer/libui/control_proxy/transformable'
26
+ require 'glimmer/libui/data_bindable'
26
27
 
27
28
  module Glimmer
28
29
  module LibUI
29
30
  class AttributedString
31
+ include DataBindable
32
+
30
33
  attr_reader :keyword, :parent_proxy, :args
31
34
  attr_accessor :block
32
35
 
@@ -86,14 +86,17 @@ module Glimmer
86
86
 
87
87
  def post_add_content
88
88
  unless parent_proxy.is_a?(Box)
89
- original_parent_proxy = @parent_proxy
90
- @vertical_box_parent_proxy = ControlProxy.create('vertical_box', parent_proxy, []) {} # block prevents calling post add content
91
- append_properties.each do |property|
92
- @vertical_box_parent_proxy.append_property(property, append_property(property))
89
+ unless @content_added
90
+ original_parent_proxy = @parent_proxy
91
+ @vertical_box_parent_proxy = ControlProxy.create('vertical_box', parent_proxy, []) {} # block prevents calling post add content
92
+ append_properties.each do |property|
93
+ @vertical_box_parent_proxy.append_property(property, append_property(property))
94
+ end
95
+ @vertical_box_parent_proxy.post_add_content
96
+ @parent_proxy = @vertical_box_parent_proxy
97
+ @vertical_box_parent_proxy.post_initialize_child(self)
98
+ @content_added = true
93
99
  end
94
- @vertical_box_parent_proxy.post_add_content
95
- @parent_proxy = @vertical_box_parent_proxy
96
- @vertical_box_parent_proxy.post_initialize_child(self)
97
100
  else
98
101
  super
99
102
  end
@@ -142,48 +145,51 @@ module Glimmer
142
145
  end
143
146
 
144
147
  def install_listeners
145
- @area_handler.Draw = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_draw_params|
146
- area_draw_params = ::LibUI::FFI::AreaDrawParams.new(area_draw_params)
147
- area_draw_params = area_draw_params_hash(area_draw_params)
148
- AreaProxy.current_area_draw_params = area_draw_params
149
- draw(area_draw_params)
150
- AreaProxy.current_area_draw_params = nil
151
- end
152
- @area_handler.MouseEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_mouse_event|
153
- area_mouse_event = ::LibUI::FFI::AreaMouseEvent.new(area_mouse_event)
154
- area_mouse_event = area_mouse_event_hash(area_mouse_event)
155
- on_mouse_event.each { |listener| listener.call(area_mouse_event)}
156
- on_mouse_move.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:x].between?(0, area_mouse_event[:area_width]) && area_mouse_event[:y].between?(0, area_mouse_event[:area_height])
157
- unless @last_area_mouse_event.nil?
158
- on_mouse_down.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:down] > 0 && @last_area_mouse_event[:down] == 0
159
- on_mouse_up.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:up] > 0 && @last_area_mouse_event[:up] == 0
160
- on_mouse_drag_start.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0 && @last_area_mouse_event[:held] == 0
161
- on_mouse_drag.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0
162
- on_mouse_drop.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] == 0 && @last_area_mouse_event[:held] > 0
148
+ unless @listeners_installed
149
+ @area_handler.Draw = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_draw_params|
150
+ area_draw_params = ::LibUI::FFI::AreaDrawParams.new(area_draw_params)
151
+ area_draw_params = area_draw_params_hash(area_draw_params)
152
+ AreaProxy.current_area_draw_params = area_draw_params
153
+ draw(area_draw_params)
154
+ AreaProxy.current_area_draw_params = nil
163
155
  end
164
- @last_area_mouse_event = area_mouse_event
165
- end
166
- @area_handler.MouseCrossed = fiddle_closure_block_caller(0, [1, 1, 4]) do |_, _, left|
167
- left = Glimmer::LibUI.integer_to_boolean(left)
168
- on_mouse_crossed.each { |listener| listener.call(left) }
169
- if left
170
- on_mouse_exit.each { |listener| listener.call(left) }
171
- else
172
- on_mouse_enter.each { |listener| listener.call(left) }
156
+ @area_handler.MouseEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_mouse_event|
157
+ area_mouse_event = ::LibUI::FFI::AreaMouseEvent.new(area_mouse_event)
158
+ area_mouse_event = area_mouse_event_hash(area_mouse_event)
159
+ on_mouse_event.each { |listener| listener.call(area_mouse_event)}
160
+ on_mouse_move.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:x].between?(0, area_mouse_event[:area_width]) && area_mouse_event[:y].between?(0, area_mouse_event[:area_height])
161
+ unless @last_area_mouse_event.nil?
162
+ on_mouse_down.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:down] > 0 && @last_area_mouse_event[:down] == 0
163
+ on_mouse_up.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:up] > 0 && @last_area_mouse_event[:up] == 0
164
+ on_mouse_drag_start.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0 && @last_area_mouse_event[:held] == 0
165
+ on_mouse_drag.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] > 0
166
+ on_mouse_drop.each { |listener| listener.call(area_mouse_event)} if area_mouse_event[:held] == 0 && @last_area_mouse_event[:held] > 0
167
+ end
168
+ @last_area_mouse_event = area_mouse_event
173
169
  end
174
- end
175
- @area_handler.DragBroken = fiddle_closure_block_caller(0, [1, 1]) do |_, _|
176
- on_drag_broken.each { |listener| listener.call }
177
- end
178
- @area_handler.KeyEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_key_event|
179
- area_key_event = ::LibUI::FFI::AreaKeyEvent.new(area_key_event)
180
- area_key_event = area_key_event_hash(area_key_event)
181
- on_key_event.each { |listener| listener.call(area_key_event) }
182
- if area_key_event[:up]
183
- on_key_up.each { |listener| listener.call(area_key_event) }
184
- else
185
- on_key_down.each { |listener| listener.call(area_key_event) }
170
+ @area_handler.MouseCrossed = fiddle_closure_block_caller(0, [1, 1, 4]) do |_, _, left|
171
+ left = Glimmer::LibUI.integer_to_boolean(left)
172
+ on_mouse_crossed.each { |listener| listener.call(left) }
173
+ if left
174
+ on_mouse_exit.each { |listener| listener.call(left) }
175
+ else
176
+ on_mouse_enter.each { |listener| listener.call(left) }
177
+ end
178
+ end
179
+ @area_handler.DragBroken = fiddle_closure_block_caller(0, [1, 1]) do |_, _|
180
+ on_drag_broken.each { |listener| listener.call }
181
+ end
182
+ @area_handler.KeyEvent = fiddle_closure_block_caller(0, [1, 1, 1]) do |_, _, area_key_event|
183
+ area_key_event = ::LibUI::FFI::AreaKeyEvent.new(area_key_event)
184
+ area_key_event = area_key_event_hash(area_key_event)
185
+ on_key_event.each { |listener| listener.call(area_key_event) }
186
+ if area_key_event[:up]
187
+ on_key_up.each { |listener| listener.call(area_key_event) }
188
+ else
189
+ on_key_down.each { |listener| listener.call(area_key_event) }
190
+ end
186
191
  end
192
+ @listeners_installed = true
187
193
  end
188
194
  end
189
195
 
@@ -28,6 +28,11 @@ 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
33
+ handle_listener('on_changed') { model_binding.call(text) } if property == 'text'
34
+ end
35
+
31
36
  def libui_api_keyword
32
37
  'entry'
33
38
  end
@@ -56,9 +56,8 @@ module Glimmer
56
56
  draw(AreaProxy.current_area_draw_params)
57
57
  destroy
58
58
  end
59
- @content_added = true
60
59
  else # image object not control
61
- build_control
60
+ build_control unless @content_added
62
61
  super
63
62
  end
64
63
  end
@@ -68,7 +67,7 @@ module Glimmer
68
67
  @args[0]
69
68
  else
70
69
  @args[0] = value
71
- if @content_added
70
+ if area_image? && @content_added
72
71
  post_add_content
73
72
  request_auto_redraw
74
73
  end
@@ -167,8 +166,8 @@ module Glimmer
167
166
  end
168
167
  canvas.resample_nearest_neighbor!(width, height) if width && height
169
168
  @data = canvas.to_rgba_stream
170
- self.width = canvas.width
171
- self.height = canvas.height
169
+ @args[1] = canvas.width
170
+ @args[2] = canvas.height
172
171
  [@data, width, height]
173
172
  end
174
173
 
@@ -28,6 +28,11 @@ 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
33
+ handle_listener('on_changed') { model_binding.call(text) } if property == 'text'
34
+ end
35
+
31
36
  def libui_api_keyword
32
37
  'multiline_entry'
33
38
  end
@@ -0,0 +1,38 @@
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/libui/control_proxy'
23
+
24
+ module Glimmer
25
+ module LibUI
26
+ class ControlProxy
27
+ # Proxy for LibUI spinbox objects
28
+ #
29
+ # Follows the Proxy Design Pattern
30
+ class SpinboxProxy < ControlProxy
31
+ def data_bind(property, model_binding)
32
+ super
33
+ handle_listener('on_changed') { model_binding.call(value) } if property == 'value'
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -55,7 +55,7 @@ module Glimmer
55
55
  end
56
56
 
57
57
  def post_add_content
58
- build_control
58
+ build_control unless @content_added
59
59
  super
60
60
  end
61
61
 
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer/libui/data_bindable'
23
+
22
24
  module Glimmer
23
25
  module LibUI
24
26
  # Proxy for LibUI control objects
@@ -101,6 +103,8 @@ module Glimmer
101
103
  end
102
104
  end
103
105
 
106
+ include DataBindable
107
+
104
108
  KEYWORD_ALIASES = {
105
109
  'msg_box' => 'message_box',
106
110
  'msg_box_error' => 'message_box_error',
@@ -136,7 +140,10 @@ module Glimmer
136
140
 
137
141
  # Subclasses may override to perform post add_content work (normally must call super)
138
142
  def post_add_content
139
- @parent_proxy&.post_initialize_child(self)
143
+ unless @content_added
144
+ @parent_proxy&.post_initialize_child(self)
145
+ @content_added = true
146
+ end
140
147
  end
141
148
 
142
149
  # Subclasses may override to perform post initialization work on an added child
@@ -0,0 +1,39 @@
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
+ module Glimmer
23
+ module LibUI
24
+ # Parent controls and shapes who have children and add child post_initialize_child
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
28
+ def data_bind(property, model_binding)
29
+ model_attribute_observer = Glimmer::DataBinding::Observer.proc do
30
+ new_value = model_binding.evaluate_property
31
+ send("#{property}=", new_value) unless send(property) == new_value
32
+ end
33
+ model_attribute_observer.observe(model_binding)
34
+ model_attribute_observer.call # initial update
35
+ model_attribute_observer
36
+ end
37
+ end
38
+ end
39
+ end
@@ -22,6 +22,7 @@
22
22
  require 'glimmer/libui/parent'
23
23
  require 'glimmer/libui/control_proxy/area_proxy'
24
24
  require 'glimmer/libui/control_proxy/path_proxy'
25
+ require 'glimmer/libui/data_bindable'
25
26
 
26
27
  module Glimmer
27
28
  module LibUI
@@ -64,6 +65,7 @@ module Glimmer
64
65
  end
65
66
 
66
67
  include Parent
68
+ include DataBindable
67
69
 
68
70
  attr_reader :parent, :args, :keyword, :block
69
71
 
@@ -79,8 +81,11 @@ module Glimmer
79
81
 
80
82
  # Subclasses may override to perform post add_content work (normally must call super)
81
83
  def post_add_content
82
- @parent&.post_initialize_child(self)
83
- @parent.post_add_content if implicit_path? && dynamic?
84
+ unless @content_added
85
+ @parent&.post_initialize_child(self)
86
+ @parent.post_add_content if implicit_path? && dynamic?
87
+ @content_added = true
88
+ end
84
89
  end
85
90
 
86
91
  def post_initialize_child(child, add_child: true)
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.1
4
+ version: 0.4.5
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-26 00:00:00.000000000 Z
11
+ date: 2021-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -223,6 +223,7 @@ files:
223
223
  - examples/basic_draw_text.rb
224
224
  - examples/basic_draw_text2.rb
225
225
  - examples/basic_entry.rb
226
+ - examples/basic_entry2.rb
226
227
  - examples/basic_image.rb
227
228
  - examples/basic_image2.rb
228
229
  - examples/basic_image3.rb
@@ -244,6 +245,7 @@ files:
244
245
  - examples/basic_transform2.rb
245
246
  - examples/basic_window.rb
246
247
  - examples/basic_window2.rb
248
+ - examples/button_counter.rb
247
249
  - examples/color_button.rb
248
250
  - examples/color_the_circles.rb
249
251
  - examples/control_gallery.rb
@@ -252,16 +254,26 @@ files:
252
254
  - examples/date_time_picker.rb
253
255
  - examples/dynamic_area.rb
254
256
  - examples/dynamic_area2.rb
257
+ - examples/dynamic_area3.rb
258
+ - examples/dynamic_area4.rb
255
259
  - examples/editable_column_table.rb
256
260
  - examples/editable_table.rb
257
261
  - examples/font_button.rb
258
262
  - examples/form.rb
263
+ - examples/form2.rb
259
264
  - examples/form_table.rb
265
+ - examples/form_table2.rb
260
266
  - examples/grid.rb
261
267
  - examples/histogram.rb
268
+ - examples/histogram2.rb
262
269
  - examples/login.rb
270
+ - examples/login2.rb
271
+ - examples/login3.rb
272
+ - examples/login4.rb
273
+ - examples/login5.rb
263
274
  - examples/meta_example.rb
264
275
  - examples/method_based_custom_keyword.rb
276
+ - examples/method_based_custom_keyword2.rb
265
277
  - examples/midi_player.rb
266
278
  - examples/simple_notepad.rb
267
279
  - examples/snake.rb
@@ -280,6 +292,7 @@ files:
280
292
  - examples/tic_tac_toe/board.rb
281
293
  - examples/tic_tac_toe/cell.rb
282
294
  - examples/timer.rb
295
+ - examples/timer2.rb
283
296
  - glimmer-dsl-libui.gemspec
284
297
  - icons/glimmer.png
285
298
  - lib/glimmer-dsl-libui.rb
@@ -357,12 +370,14 @@ files:
357
370
  - lib/glimmer/libui/control_proxy/open_type_tag_proxy.rb
358
371
  - lib/glimmer/libui/control_proxy/path_proxy.rb
359
372
  - lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb
373
+ - lib/glimmer/libui/control_proxy/spinbox_proxy.rb
360
374
  - lib/glimmer/libui/control_proxy/tab_item_proxy.rb
361
375
  - lib/glimmer/libui/control_proxy/table_proxy.rb
362
376
  - lib/glimmer/libui/control_proxy/text_proxy.rb
363
377
  - lib/glimmer/libui/control_proxy/transformable.rb
364
378
  - lib/glimmer/libui/control_proxy/triple_column.rb
365
379
  - lib/glimmer/libui/control_proxy/window_proxy.rb
380
+ - lib/glimmer/libui/data_bindable.rb
366
381
  - lib/glimmer/libui/image_path_renderer.rb
367
382
  - lib/glimmer/libui/parent.rb
368
383
  - lib/glimmer/libui/shape.rb