fxruby-enhancement 0.1.0 → 0.2.0

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