glimmer-dsl-libui 0.2.21 → 0.3.0

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