fxruby-enhancement 0.1.0 → 0.2.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.
@@ -0,0 +1,336 @@
1
+ # coding: utf-8
2
+ require_relative 'charting-boxes'
3
+
4
+ module Fox
5
+ module Enhancement
6
+ module Xtras
7
+ # Charting constructs. Note that the
8
+ # rulers have built-in their own labeling, with orientation.
9
+ module Charting
10
+ # range in real coordinates, beginning and end points
11
+ class Range
12
+ attr_accessor :x1, :y1, :x2, :y2
13
+
14
+ def initialize x1, y1, x2, y2
15
+ @x1 = x1
16
+ @y1 = y1
17
+ @x2 = x2
18
+ @y2 = y2
19
+ end
20
+ end
21
+
22
+ class Chart
23
+ extend Forwardable
24
+ include RGB
25
+
26
+ def_delegators :@canvas, :width, :height, :visual
27
+ def_delegators :@cos, :type,
28
+ :axial, :data, :series, :domain, :range,
29
+ :background, :caption, :title
30
+
31
+ attr_accessor :buffer, :x_range, :y_range
32
+
33
+ def initialize cos, canvas
34
+ @cos = cos
35
+ @canvas = canvas
36
+ as (:app) {
37
+ @buffer = fx_image { opts IMAGE_KEEP }
38
+ }
39
+ # detailed chart parameters
40
+ @x_ruler_width = 20
41
+ @y_ruler_height = 20
42
+ @font_title = nil
43
+ @font_caption = nil
44
+ @font_ledgend = nil
45
+ @font_axis_name = nil
46
+
47
+ # chart layout
48
+ lytbox = ->(klass, **kv){ [kv[:name], klass.new(self, **kv)] }
49
+ @layout = lyt = [
50
+ lytbox.(NullBox, name: :null_left, placement: :left),
51
+ lytbox.(NullBox, name: :null_right, placement: :right),
52
+ lytbox.(NullBox, name: :null_top, placement: :top),
53
+ lytbox.(NullBox, name: :null_bottom, placement: :bottom),
54
+ lytbox.(Title, name: :title, float: true),
55
+ lytbox.(Ruler, name: :top_ruler, orient: :horizontal, placement: :top),
56
+ lytbox.(Ruler, name: :bottom_ruler, orient: :horizontal, placement: :bottom),
57
+ lytbox.(Ruler, name: :left_ruler, orient: :vertical, placement: :left),
58
+ lytbox.(Ruler, name: :right_ruler, orient: :vertical, placement: :right),
59
+ lytbox.(Caption, name: :caption, float: true),
60
+ lytbox.(Legend, name: :legend, float: true),
61
+ lytbox.(Graph, name: :graph)
62
+ ].to_h
63
+
64
+ # bottom connections
65
+ lyt[:null_top].bottom_box = lyt[:title]
66
+ lyt[:title].bottom_box = lyt[:top_ruler]
67
+ lyt[:top_ruler].bottom_box = lyt[:graph]
68
+ lyt[:graph].bottom_box = lyt[:bottom_ruler]
69
+ lyt[:bottom_ruler].bottom_box = lyt[:caption]
70
+ lyt[:caption].bottom_box = lyt[:null_bottom]
71
+
72
+ # right connections
73
+ lyt[:null_left].right_box = lyt[:left_ruler]
74
+ lyt[:left_ruler].right_box = lyt[:graph]
75
+ lyt[:graph].right_box = lyt[:right_ruler]
76
+ lyt[:right_ruler].right_box = lyt[:legend]
77
+ lyt[:legend].right_box = lyt[:null_right]
78
+
79
+ backlink_boxes
80
+ end
81
+
82
+ def backlink_boxes
83
+ @layout.each{ |name, box|
84
+ box.bottom_box.top_box = box unless box.bottom_box.nil?
85
+ box.right_box.left_box = box unless box.right_box.nil?
86
+ }
87
+ end
88
+
89
+ # call inially and when there's an update.
90
+ def layout_boxes
91
+ clear_all_boxes
92
+ recalculate_dimensions
93
+
94
+ # first pass -- out to in
95
+ (0..Box::MAX_DOMINANCE).each do |dom|
96
+ boxes_of_dominance(dom).each{ |box| layout_box box }
97
+ end
98
+
99
+ # second pass -- in to out
100
+ (1..Box::MAX_DOMINANCE).to_a.reverse.each do |dom|
101
+ boxes_of_dominance(dom).each{ |box| layout_box box }
102
+ end
103
+ end
104
+
105
+ # All x,y,width,height are nilled for all boxes
106
+ def clear_all_boxes
107
+ @layout.each { |name, box|
108
+ box.x = box.y = box.width = box.height = nil
109
+ }
110
+ end
111
+
112
+ def recalculate_dimensions
113
+ @layout.each { |name, box|
114
+ box.calculate_dimensions
115
+ }
116
+ end
117
+
118
+ # Layout given box, as much as possible, given neighbors.
119
+ # may be called twice per box.
120
+ #
121
+ def layout_box box
122
+ if box.dominance == 0 # the only box with a dom of 0 are the null boxes
123
+ case box.name
124
+ when :null_left
125
+ box.x = 0
126
+ box.y = 0
127
+ box.width = 0
128
+ box.height = height
129
+ when :null_right
130
+ box.x = width
131
+ box.y = 0
132
+ box.width = 0
133
+ box.height = height
134
+ when :null_top
135
+ box.x = 0
136
+ box.y = 0
137
+ box.width = width
138
+ box.height = 0
139
+ when :null_bottom
140
+ box.x = 0
141
+ box.y = height
142
+ box.width = width
143
+ box.height = 0
144
+ end
145
+ else # we do what we can.
146
+ box.calculate_dimensions
147
+ subordinates(box).each { |sub|
148
+ begin
149
+ case sub
150
+ when box.left_box
151
+ box.x = sub.x + sub.width + sub.right_margin + box.left_margin
152
+ when box.right_box
153
+ box.x = sub.x - sub.left_margin - box.right_margin - box.width
154
+ when box.top_box
155
+ box.y = sub.y + sub.height + sub.bottom_margin + box.top_margin
156
+ when box.bottom_box
157
+ box.y = sub.y - sub.top_margin - box.bottom_margin - box.height
158
+ end
159
+ rescue NoMethodError, TypeError => e
160
+ #puts "-->subortinate unresolved: #{e}"
161
+ end
162
+ }
163
+
164
+ superiors(box).each { |sup|
165
+ begin
166
+ case sup
167
+ when box.left_box
168
+ box.height = sup.height
169
+ box.y = sup.y
170
+ box.x = sup.x + sup.width + sup.right_margin + box.left_margin
171
+ when box.right_box
172
+ box.height = sup.height
173
+ box.y = sup.y
174
+ when box.top_box
175
+ box.width = sup.width
176
+ box.x = sup.x
177
+ when box.bottom_box
178
+ box.width = sup.width
179
+ box.x = sup.x
180
+ end
181
+ rescue NoMethodError, TypeError => e
182
+ #puts "-->superior unresolved: #{e}"
183
+ end unless box.floating?
184
+ }
185
+ end
186
+ end
187
+
188
+ # Give a list of subordinates
189
+ def subordinates box
190
+ Box::NÄHE.map{ |b| box.send(b) }
191
+ .compact
192
+ .select { |nbox| box.dominance > nbox.dominance }
193
+ end
194
+
195
+ # Give a list of superiors
196
+ def superiors box
197
+ Box::NÄHE.map{ |b| box.send(b) }
198
+ .compact
199
+ .select { |nbox| box.dominance < nbox.dominance }
200
+ end
201
+
202
+ # return all boxes with the proscribed dominance
203
+ def boxes_of_dominance dom
204
+ @layout.map{ |name, box| box }.select{ |box| box.dominance == dom }
205
+ end
206
+
207
+ def draw_dc &block
208
+ @buffer.starten if @buffer.inst.nil?
209
+ FXDCWindow.new(@buffer.inst) { |dc| block.(dc) }
210
+ end
211
+
212
+ def update_chart
213
+ layout_boxes
214
+ draw_dc { |dc|
215
+ dc.setForeground white
216
+ dc.fillRectangle 0, 0, width, height
217
+ dc.drawImage @buffer.inst, 0, 0
218
+ @layout.each{ |name, box| box.render(dc) }
219
+ }
220
+ @canvas.update
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ module Mapper
227
+ def fx_chart name = nil,
228
+ ii: 0,
229
+ pos: Enhancement.stack.last,
230
+ reuse: nil,
231
+ &block
232
+ Enhancement.stack << (@os = os =
233
+ OpenStruct.new(klass: FXCanvas,
234
+ op: [],
235
+ ii: ii,
236
+ fx: nil,
237
+ kinder: [],
238
+ inst: nil,
239
+ instance_result: nil,
240
+ reusable: reuse,
241
+ type: :cartesian,
242
+ axial: OpenStruct.new,
243
+ background: OpenStruct.new,
244
+ caption: OpenStruct.new,
245
+ title: OpenStruct.new))
246
+ Enhancement.components[name] = os unless name.nil?
247
+ unless pos.nil?
248
+ pos.kinder << os
249
+ else
250
+ Enhancement.base = os
251
+ end
252
+
253
+ @os.op[0] = OpenStruct.new(:parent => :required,
254
+ :target => nil,
255
+ :selector => 0,
256
+ :opts => FRAME_NORMAL,
257
+ :x => 0,
258
+ :y => 0,
259
+ :width => 0,
260
+ :height => 0)
261
+
262
+ # Initializers for the underlying
263
+ def target var; @os.op[@os.ii].target = var; end
264
+ def selector var; @os.op[@os.ii].selector = var; end
265
+ def opts var; @os.op[@os.ii].opts = var; end
266
+ def x var; @os.op[@os.ii].x = var; end
267
+ def y var; @os.op[@os.ii].y = var; end
268
+ def width var; @os.op[@os.ii].width = var; end
269
+ def height var; @os.op[@os.ii].height = var; end
270
+
271
+ # Chart specific
272
+ def type var; @os.type = var; end
273
+
274
+ def axis ax, **kv
275
+ @os.axial[ax] = OpenStruct.new(**kv)
276
+ end
277
+
278
+ def data *dat; @os.data = dat; end
279
+ def series ser; @os.series = ser; end
280
+ def domain a, b; @os.domain = [a, b]; end
281
+ def range a, b; @os.range = [a, b]; end
282
+
283
+ def background **kv; kv.each{ |k,v| @os.background[k] = v }; end
284
+ def caption **kv; kv.each{ |k,v| @os.caption[k] = v }; end
285
+ def title **kv; kv.each{ |k,v| @os.title[k] = v }; end
286
+
287
+ # What will be executed after FXCanvas is created.
288
+ def instance aname=nil, &block
289
+ @os.instance_name = aname
290
+ @os.instance_block ||= []
291
+ @os.instance_block << [aname, block]
292
+ end
293
+
294
+ # Internal use only.
295
+ def chart_instance os, &block
296
+ os.instance_name = nil
297
+ os.instance_block ||= []
298
+ os.instance_block << [nil, block]
299
+ return os
300
+ end
301
+
302
+ self.instance_eval &block
303
+
304
+ os.fx = ->(){
305
+ chart_instance (os) { |c|
306
+ os.chart = Xtras::Charting::Chart.new os, c
307
+ os.inst.instance_variable_set(:@chart, os.chart)
308
+ }
309
+
310
+ c = FXCanvas.new(*([pos.inst] + os.op[os.ii].to_h.values[1..-1]
311
+ .map{ |v| (v.is_a?(OpenStruct) ? v.inst : v)} ))
312
+ c.extend SingleForwardable
313
+ c.def_delegators :@chart, :update_chart
314
+ c.sel_configure { |sender, sel, event|
315
+ os.chart.buffer.starten if os.chart.buffer.inst.nil?
316
+ bb = os.chart.buffer.inst
317
+ bb.create unless bb.created?
318
+ bb.resize sender.width, sender.height
319
+ }
320
+ c.sel_paint { |sender, sel, event|
321
+ FXDCWindow.new(sender, event) { |dc|
322
+ os.chart.buffer.starten if os.chart.buffer.inst.nil?
323
+ dc.drawImage(os.chart.buffer.inst, 0, 0)
324
+ }
325
+ }
326
+ c
327
+ }
328
+
329
+ Enhancement.stack.pop
330
+ @os = Enhancement.stack.last
331
+ return os
332
+ end
333
+ end
334
+ end
335
+ end
336
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fxruby-enhancement
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Mitchell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-20 00:00:00.000000000 Z
11
+ date: 2017-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: semver2
@@ -86,6 +86,20 @@ dependencies:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rgb
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
89
103
  - !ruby/object:Gem::Dependency
90
104
  name: rspec
91
105
  requirement: !ruby/object:Gem::Requirement
@@ -283,15 +297,30 @@ files:
283
297
  - examples/.ruby-version
284
298
  - examples/bounce.rb
285
299
  - examples/data_target.rb
300
+ - examples/debug
286
301
  - examples/dialog_box.rb
287
302
  - examples/hello.rb
303
+ - examples/images/bounce.rb.png
304
+ - examples/images/data_target.rb.png
305
+ - examples/images/dialog_box.rb.png
306
+ - examples/images/hello-world-new-and-old.png
307
+ - examples/images/hello.rb.png
308
+ - examples/images/rubyneat-panel.png
309
+ - examples/images/scribble.rb.png
310
+ - examples/scribble.rb
288
311
  - fxruby-enhancement.gemspec
289
312
  - lib/fxruby-enhancement.rb
290
313
  - lib/fxruby-enhancement/api-mapper.rb
291
314
  - lib/fxruby-enhancement/api-mapper.rb.erb
315
+ - lib/fxruby-enhancement/color-mapper.rb
316
+ - lib/fxruby-enhancement/color-mapper.rb.erb
292
317
  - lib/fxruby-enhancement/core-monkey.rb
293
318
  - lib/fxruby-enhancement/enhancement.rb
294
319
  - lib/fxruby-enhancement/ostruct-monkey.rb
320
+ - lib/fxruby-enhancement/rgb-monkey.rb
321
+ - lib/fxruby-enhancement/xtras.rb
322
+ - lib/fxruby-enhancement/xtras/charting-boxes.rb
323
+ - lib/fxruby-enhancement/xtras/charting.rb
295
324
  - spec/fxruby-enhancement_spec.rb
296
325
  - spec/spec_helper.rb
297
326
  homepage: http://github.com/flajann2/fxruby-enhancement