glimmer-dsl-libui 0.2.21 → 0.3.0

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.
@@ -20,44 +20,184 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/libui/control_proxy'
23
+ require 'glimmer/libui/image_path_renderer'
23
24
  require 'glimmer/data_binding/observer'
25
+ require 'glimmer/libui/control_proxy/transformable'
24
26
 
25
27
  using ArrayIncludeMethods
26
28
 
27
29
  module Glimmer
28
30
  module LibUI
29
31
  class ControlProxy
30
- # Proxy for LibUI image objects
32
+ # Proxy for LibUI image object and Glimmer custom control
31
33
  #
32
34
  # Follows the Proxy Design Pattern
33
35
  class ImageProxy < ControlProxy
36
+ include Parent
37
+ prepend Transformable
38
+
39
+ attr_reader :data, :pixels, :shapes
40
+
34
41
  def initialize(keyword, parent, args, &block)
35
42
  @keyword = keyword
36
43
  @parent_proxy = parent
37
44
  @args = args
38
45
  @block = block
39
46
  @enabled = true
40
- @children = []
41
47
  post_add_content if @block.nil?
42
48
  end
43
-
49
+
44
50
  def post_add_content
45
- build_control
46
- super
51
+ if area_image?
52
+ @shapes = nil
53
+ super
54
+ if @parent_proxy.nil? && AreaProxy.current_area_draw_params
55
+ draw(AreaProxy.current_area_draw_params)
56
+ destroy
57
+ end
58
+ @content_added = true
59
+ else # image object not control
60
+ build_control
61
+ super
62
+ end
63
+ end
64
+
65
+ def file(value = nil)
66
+ if area_image?
67
+ if value.nil?
68
+ @args[0]
69
+ else
70
+ @args[0] = value
71
+ if @content_added
72
+ post_add_content
73
+ request_auto_redraw
74
+ end
75
+ end
76
+ end
47
77
  end
48
-
49
- def post_initialize_child(child)
50
- @children << child
78
+ alias file= file
79
+ alias set_file file
80
+
81
+ def width(value = nil)
82
+ if value.nil?
83
+ area_image? ? @args[1] : @args[0]
84
+ else
85
+ if area_image?
86
+ @args[1] = value
87
+ if @content_added
88
+ post_add_content
89
+ request_auto_redraw
90
+ end
91
+ else
92
+ @args[0] = value
93
+ end
94
+ end
95
+ end
96
+ alias width= width
97
+ alias set_width width
98
+
99
+ def height(value = nil)
100
+ if value.nil?
101
+ area_image? ? @args[2] : @args[1]
102
+ else
103
+ if area_image?
104
+ @args[2] = value
105
+ if @content_added
106
+ post_add_content
107
+ request_auto_redraw
108
+ end
109
+ else
110
+ @args[1] = value
111
+ end
112
+ end
113
+ end
114
+ alias height= height
115
+ alias set_height height
116
+
117
+ def redraw
118
+ @parent_proxy&.redraw
119
+ end
120
+
121
+ def request_auto_redraw
122
+ @parent_proxy&.request_auto_redraw if area_image?
123
+ end
124
+
125
+ def draw(area_draw_params)
126
+ if @shapes.nil?
127
+ load_image
128
+ parse_pixels
129
+ calculate_shapes
130
+ end
131
+ ImagePathRenderer.new(@parent_proxy, @shapes).render
132
+ end
133
+
134
+ def area_image?
135
+ @parent_proxy&.is_a?(AreaProxy) or
136
+ AreaProxy.current_area_draw_params or
137
+ @args[0].is_a?(String) # first arg is file
138
+ end
139
+
140
+ def destroy
141
+ @parent_proxy&.children&.delete(self)
142
+ ControlProxy.control_proxies.delete(self)
51
143
  end
52
144
 
53
145
  private
54
146
 
55
147
  def build_control
56
- @args = [@children.first.args[1], @children.first.args[2]] if @children.size == 1 && (@args[0].nil? || @args[1].nil?)
57
- super
58
- @libui.tap do
59
- @children.each {|child| child&.send(:build_control) }
148
+ unless area_image? # image object
149
+ @args = [@children.first.args[1], @children.first.args[2]] if @children.size == 1 && (@args[0].nil? || @args[1].nil?)
150
+ super
151
+ @libui.tap do
152
+ @children.each {|child| child&.send(:build_control) }
153
+ end
154
+ end
155
+ end
156
+
157
+ def load_image
158
+ require 'chunky_png'
159
+ f = File.open(file)
160
+ canvas = ChunkyPNG::Canvas.from_io(f)
161
+ f.close
162
+ canvas.resample_nearest_neighbor!(width, height) if width && height
163
+ @data = canvas.to_rgba_stream
164
+ self.width = canvas.width
165
+ self.height = canvas.height
166
+ end
167
+
168
+ def parse_pixels
169
+ @pixels = height.times.map do |y|
170
+ width.times.map do |x|
171
+ r = @data[(y*width + x)*4].ord
172
+ g = @data[(y*width + x)*4 + 1].ord
173
+ b = @data[(y*width + x)*4 + 2].ord
174
+ a = @data[(y*width + x)*4 + 3].ord
175
+ {x: x, y: y, color: {r: r, g: g, b: b, a: a}}
176
+ end
177
+ end.flatten
178
+ end
179
+
180
+ def calculate_shapes
181
+ @shapes = []
182
+ original_pixels = @pixels.dup
183
+ indexed_original_pixels = Hash[original_pixels.each_with_index.to_a]
184
+ @pixels.each do |pixel|
185
+ index = indexed_original_pixels[pixel]
186
+ @rectangle_start_x ||= pixel[:x]
187
+ @rectangle_width ||= 1
188
+ if pixel[:x] < width - 1 && pixel[:color] == original_pixels[index + 1][:color]
189
+ @rectangle_width += 1
190
+ else
191
+ if pixel[:x] > 0 && pixel[:color] == original_pixels[index - 1][:color]
192
+ @shapes << {x: @rectangle_start_x, y: pixel[:y], width: @rectangle_width, height: 1, color: pixel[:color]}
193
+ else
194
+ @shapes << {x: pixel[:x], y: pixel[:y], width: 1, height: 1, color: pixel[:color]}
195
+ end
196
+ @rectangle_width = 1
197
+ @rectangle_start_x = pixel[:x] == width - 1 ? 0 : pixel[:x] + 1
198
+ end
60
199
  end
200
+ @shapes
61
201
  end
62
202
  end
63
203
  end
@@ -45,7 +45,7 @@ module Glimmer
45
45
 
46
46
  def destroy
47
47
  super
48
- ControlProxy.image_proxies.each { |image_proxy| ::LibUI.free_image(image_proxy.libui) }
48
+ ControlProxy.image_proxies.each { |image_proxy| ::LibUI.free_image(image_proxy.libui) unless image_proxy.area_image? }
49
49
  @on_destroy_procs&.each { |on_destroy_proc| on_destroy_proc.call(self)}
50
50
  end
51
51
 
@@ -27,8 +27,8 @@ module Glimmer
27
27
  class ControlProxy
28
28
  class << self
29
29
  def exists?(keyword)
30
- ::LibUI.respond_to?("new_#{keyword}") ||
31
- ::LibUI.respond_to?(keyword) ||
30
+ ::LibUI.respond_to?("new_#{keyword}") or
31
+ ::LibUI.respond_to?(keyword) or
32
32
  descendant_keyword_constant_map.keys.include?(keyword)
33
33
  end
34
34
 
@@ -207,11 +207,11 @@ module Glimmer
207
207
  end
208
208
 
209
209
  def respond_to_libui?(method_name, *args, &block)
210
- ::LibUI.respond_to?("control_#{method_name}") ||
211
- (::LibUI.respond_to?("control_#{method_name.to_s.sub(/\?$/, '')}") && BOOLEAN_PROPERTIES.include?(method_name.to_s.sub(/\?$/, '')) ) ||
212
- ::LibUI.respond_to?("control_set_#{method_name.to_s.sub(/=$/, '')}") ||
213
- ::LibUI.respond_to?("#{libui_api_keyword}_#{method_name}") ||
214
- (::LibUI.respond_to?("#{libui_api_keyword}_#{method_name.to_s.sub(/\?$/, '')}") && BOOLEAN_PROPERTIES.include?(method_name.to_s.sub(/\?$/, '')) ) ||
210
+ ::LibUI.respond_to?("control_#{method_name}") or
211
+ (::LibUI.respond_to?("control_#{method_name.to_s.sub(/\?$/, '')}") && BOOLEAN_PROPERTIES.include?(method_name.to_s.sub(/\?$/, '')) ) or
212
+ ::LibUI.respond_to?("control_set_#{method_name.to_s.sub(/=$/, '')}") or
213
+ ::LibUI.respond_to?("#{libui_api_keyword}_#{method_name}") or
214
+ (::LibUI.respond_to?("#{libui_api_keyword}_#{method_name.to_s.sub(/\?$/, '')}") && BOOLEAN_PROPERTIES.include?(method_name.to_s.sub(/\?$/, '')) ) or
215
215
  ::LibUI.respond_to?("#{libui_api_keyword}_set_#{method_name.to_s.sub(/=$/, '')}")
216
216
  end
217
217
 
@@ -0,0 +1,30 @@
1
+ module Glimmer
2
+ module LibUI
3
+ class ImagePathRenderer
4
+ include Glimmer
5
+
6
+ def initialize(area_proxy, shapes)
7
+ @area_proxy = area_proxy
8
+ @shapes = shapes
9
+ end
10
+
11
+ def render
12
+ work = Proc.new do
13
+ @shapes.each do |shape|
14
+ path {
15
+ rectangle(shape[:x], shape[:y], shape[:width], shape[:height])
16
+
17
+ fill shape[:color]
18
+ }
19
+ end
20
+ end
21
+ if @area_proxy.nil?
22
+ # Ensure it renders without a parent
23
+ Glimmer::DSL::Engine.add_content(nil, Glimmer::DSL::Libui::ControlExpression.new, 'image', &work)
24
+ else
25
+ work.call
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/glimmer/libui.rb CHANGED
@@ -26,12 +26,12 @@ module Glimmer
26
26
  class << self
27
27
  include Glimmer::FiddleConsumer
28
28
 
29
- def integer_to_boolean(int, allow_nil: true)
30
- int.nil? ? (allow_nil ? nil : false) : ((int.is_a?(TrueClass) || int.is_a?(FalseClass)) ? int : (int.is_a?(Integer) ? int == 1 : (allow_nil ? nil : false)))
29
+ def integer_to_boolean(int, allow_nil: true, allow_boolean: true)
30
+ int.nil? ? (allow_nil ? nil : false) : (allow_boolean && (int.is_a?(TrueClass) || int.is_a?(FalseClass)) ? int : (int.is_a?(Integer) ? int == 1 : (allow_nil ? nil : false)))
31
31
  end
32
32
 
33
- def boolean_to_integer(bool, allow_nil: true)
34
- bool.nil? ? (allow_nil ? nil : 0) : (bool.is_a?(Integer) ? bool : (bool.is_a?(TrueClass) || bool.is_a?(FalseClass) ? (bool == true ? 1 : 0) : (allow_nil ? nil : 0)))
33
+ def boolean_to_integer(bool, allow_nil: true, allow_integer: true)
34
+ bool.nil? ? (allow_nil ? nil : 0) : (allow_integer && bool.is_a?(Integer) ? bool : (bool.is_a?(TrueClass) || bool.is_a?(FalseClass) ? (bool == true ? 1 : 0) : (allow_nil ? nil : 0)))
35
35
  end
36
36
 
37
37
  def degrees_to_radians(degrees)
@@ -83,6 +83,7 @@ module Glimmer
83
83
  value = value.chars.map {|char| [char, char]}.flatten.join if value.length == 3
84
84
  value = "0x#{value}"
85
85
  end
86
+ value = "0x#{value[1..-1]}" if value.start_with?('#')
86
87
  value = value.to_i(16)
87
88
  end
88
89
  if value.is_a?(Integer)
@@ -173,7 +174,7 @@ module Glimmer
173
174
  # If block returns true at any point, the timer continues for another repetition regardless of `repeat:` keyword arg value
174
175
  def timer(time_in_seconds = 0.1, repeat: true, &block)
175
176
  closure = fiddle_closure_block_caller(4, [0]) do
176
- result = boolean_to_integer(block.call)
177
+ result = boolean_to_integer(block.call, allow_integer: false)
177
178
  repeat -= 1 if repeat.is_a?(Integer)
178
179
  if result.nil?
179
180
  if (repeat == true || (repeat.is_a?(Integer) && repeat > 0))
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.2.21
4
+ version: 0.3.0
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-05 00:00:00.000000000 Z
11
+ date: 2021-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.4.0
19
+ version: 2.4.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.4.0
26
+ version: 2.4.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: os
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: 0.0.12
75
+ - !ruby/object:Gem::Dependency
76
+ name: chunky_png
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: 1.4.0
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 1.4.0
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: juwelier
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -221,6 +235,11 @@ files:
221
235
  - examples/basic_draw_text.rb
222
236
  - examples/basic_draw_text2.rb
223
237
  - examples/basic_entry.rb
238
+ - examples/basic_image.rb
239
+ - examples/basic_image2.rb
240
+ - examples/basic_image3.rb
241
+ - examples/basic_image4.rb
242
+ - examples/basic_image5.rb
224
243
  - examples/basic_table.rb
225
244
  - examples/basic_table_button.rb
226
245
  - examples/basic_table_checkbox.rb
@@ -252,6 +271,13 @@ files:
252
271
  - examples/method_based_custom_keyword.rb
253
272
  - examples/midi_player.rb
254
273
  - examples/simple_notepad.rb
274
+ - examples/snake.rb
275
+ - examples/snake/model/apple.rb
276
+ - examples/snake/model/game.rb
277
+ - examples/snake/model/snake.rb
278
+ - examples/snake/model/vertebra.rb
279
+ - examples/snake/presenter/cell.rb
280
+ - examples/snake/presenter/grid.rb
255
281
  - examples/tetris.rb
256
282
  - examples/tetris/model/block.rb
257
283
  - examples/tetris/model/game.rb
@@ -340,6 +366,7 @@ files:
340
366
  - lib/glimmer/libui/control_proxy/transformable.rb
341
367
  - lib/glimmer/libui/control_proxy/triple_column.rb
342
368
  - lib/glimmer/libui/control_proxy/window_proxy.rb
369
+ - lib/glimmer/libui/image_path_renderer.rb
343
370
  - lib/glimmer/libui/parent.rb
344
371
  - lib/glimmer/libui/shape.rb
345
372
  - lib/glimmer/libui/shape/arc.rb