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.
- checksums.yaml +4 -4
- data/.semver +1 -1
- data/Gemfile +5 -4
- data/Gemfile.lock +8 -7
- data/README.org +492 -13
- data/build/scrape-rdoc.rb +288 -0
- data/examples/bounce.rb +4 -2
- data/examples/data_target.rb +0 -0
- data/examples/debug +10 -0
- data/examples/dialog_box.rb +0 -0
- data/examples/hello.rb +0 -0
- data/examples/images/bounce.rb.png +0 -0
- data/examples/images/data_target.rb.png +0 -0
- data/examples/images/dialog_box.rb.png +0 -0
- data/examples/images/hello-world-new-and-old.png +0 -0
- data/examples/images/hello.rb.png +0 -0
- data/examples/images/rubyneat-panel.png +0 -0
- data/examples/images/scribble.rb.png +0 -0
- data/examples/scribble.rb +175 -0
- data/fxruby-enhancement.gemspec +21 -3
- data/lib/fxruby-enhancement.rb +4 -1
- data/lib/fxruby-enhancement/api-mapper.rb +4967 -3793
- data/lib/fxruby-enhancement/api-mapper.rb.erb +17 -12
- data/lib/fxruby-enhancement/color-mapper.rb +1103 -0
- data/lib/fxruby-enhancement/color-mapper.rb.erb +23 -0
- data/lib/fxruby-enhancement/enhancement.rb +41 -2
- data/lib/fxruby-enhancement/ostruct-monkey.rb +18 -3
- data/lib/fxruby-enhancement/rgb-monkey.rb +54 -0
- data/lib/fxruby-enhancement/xtras.rb +1 -0
- data/lib/fxruby-enhancement/xtras/charting-boxes.rb +247 -0
- data/lib/fxruby-enhancement/xtras/charting.rb +336 -0
- metadata +31 -2
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
=begin rdoc
|
3
|
+
This is a color map for Enhancement to make it
|
4
|
+
easier to deal with colors in FXRuby.
|
5
|
+
|
6
|
+
To use, just do:
|
7
|
+
include RGB
|
8
|
+
== List of available colors
|
9
|
+
<% for @fxcolor, @fxstring in @fxc %>
|
10
|
+
* <%= @fxcolor.snake %>
|
11
|
+
<% end %>
|
12
|
+
|
13
|
+
== NOTE WELL
|
14
|
+
This file is generated by fxruby-enhancement.
|
15
|
+
Do NOT modify this file. Modify the ERB template
|
16
|
+
file instead, and run 'rake scrape'.
|
17
|
+
=end
|
18
|
+
|
19
|
+
module RGB
|
20
|
+
<% for @fxcolor, @fxstring in @fxc %>
|
21
|
+
def <%= @fxcolor.snake %>; <%= @fxstring %>; end
|
22
|
+
<% end %>
|
23
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
module Fox
|
3
2
|
|
4
3
|
# Include this in your top class objects.
|
@@ -9,10 +8,12 @@ module Fox
|
|
9
8
|
@stack = []
|
10
9
|
@base = nil
|
11
10
|
@components = {}
|
11
|
+
@kinder_parents = {}
|
12
12
|
SPECIAL = [:FXApp,
|
13
13
|
:FXColorItem,
|
14
14
|
:FXRegion,
|
15
15
|
:FXRectangle,
|
16
|
+
:FXPoint,
|
16
17
|
:FXGradient,
|
17
18
|
:FXEvent,
|
18
19
|
:FXDataTarget,
|
@@ -23,6 +24,7 @@ module Fox
|
|
23
24
|
# Module-level
|
24
25
|
class << self
|
25
26
|
attr_accessor :stack,
|
27
|
+
:kinder_parents, # this is to make 'as' delecrations work intuitively.
|
26
28
|
:base, # the very first component declared, usually the app.
|
27
29
|
:components,
|
28
30
|
:deferred_setups,
|
@@ -97,6 +99,9 @@ module Fox
|
|
97
99
|
end
|
98
100
|
return inst
|
99
101
|
end
|
102
|
+
|
103
|
+
def rgb
|
104
|
+
end
|
100
105
|
|
101
106
|
# Find the referenced component's wrapper object
|
102
107
|
def refc sym, &block
|
@@ -128,6 +133,31 @@ module Fox
|
|
128
133
|
end
|
129
134
|
alias_method :fxi, :fox_instance
|
130
135
|
|
136
|
+
# To allow for adding new components at
|
137
|
+
# other places other than the immediate
|
138
|
+
# parental nesting.
|
139
|
+
def as tag, kpos: Enhancement.stack.last, &block
|
140
|
+
Enhancement.stack << (@os = os = refc(tag))
|
141
|
+
|
142
|
+
# We must add our actual parent to the kinder parent
|
143
|
+
# registry, and remove it before we're done here.
|
144
|
+
kstacklvl = Enhancement.stack.size + 1
|
145
|
+
Enhancement.kinder_parents[kstacklvl] = kpos
|
146
|
+
|
147
|
+
def instance a=nil, &block
|
148
|
+
@os.instance_name = a
|
149
|
+
@os.instance_block ||= []
|
150
|
+
@os.instance_block << [a, block]
|
151
|
+
end
|
152
|
+
|
153
|
+
self.instance_eval &block
|
154
|
+
|
155
|
+
Enhancement.kinder_parents.delete kstacklvl
|
156
|
+
Enhancement.stack.pop
|
157
|
+
@os = Enhancement.stack.last
|
158
|
+
return os
|
159
|
+
end
|
160
|
+
|
131
161
|
# Handles incomming external messages of type given
|
132
162
|
# block, written by user, is called with |type, message|.
|
133
163
|
# Zero or more symbols may be given,
|
@@ -148,7 +178,16 @@ module Fox
|
|
148
178
|
# TODO: Not sure we need this. This may go away.
|
149
179
|
def deferred_setup &block
|
150
180
|
Enhancement.deferred_setups << block
|
151
|
-
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# This simplifies creating the FXDCWindow object.
|
184
|
+
def fx_dc tag, event=nil, &block
|
185
|
+
unless event.nil?
|
186
|
+
FXDCWindow.new(ref(tag), event) { |dc| block.(dc) }
|
187
|
+
else
|
188
|
+
FXDCWindow.new(ref(tag)) { |dc| block.(dc) }
|
189
|
+
end
|
190
|
+
end
|
152
191
|
end
|
153
192
|
end
|
154
193
|
end
|
@@ -16,6 +16,7 @@ class OpenStruct
|
|
16
16
|
def create_fox_components use_as_base = nil
|
17
17
|
if use_as_base.nil?
|
18
18
|
self.inst = fx.() if self.inst.nil?
|
19
|
+
self.as_tasks.map{ |a| a.() } unless self.as_tasks.nil?
|
19
20
|
self.kinder.each{ |os|
|
20
21
|
os.create_fox_components unless os.reusable?
|
21
22
|
}
|
@@ -38,13 +39,27 @@ class OpenStruct
|
|
38
39
|
}
|
39
40
|
self.inst = nil
|
40
41
|
end
|
41
|
-
|
42
|
+
|
43
|
+
# We can have as many instances as we like.
|
42
44
|
def instance_final_activate
|
43
|
-
self.instance_result =
|
44
|
-
|
45
|
+
self.instance_result =
|
46
|
+
self.instance_block.map{ |name, inst|
|
47
|
+
inst.(self.inst)
|
48
|
+
} unless self.instance_block.nil?
|
49
|
+
self.kinder
|
50
|
+
.each{ |os|
|
51
|
+
os.instance_final_activate unless os.reusable?
|
52
|
+
}
|
45
53
|
self
|
46
54
|
end
|
47
55
|
|
56
|
+
# We must insure that instance actually is something
|
57
|
+
# other than nil.
|
58
|
+
def instance
|
59
|
+
raise "Instance is not set for #{self.klass}" if self.inst.nil?
|
60
|
+
self.inst
|
61
|
+
end
|
62
|
+
|
48
63
|
# launch the application
|
49
64
|
def launch ingress: false
|
50
65
|
create_fox_components
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
=begin rdoc
|
3
|
+
color = RGB::Color.from_rgb_hex("#333333")
|
4
|
+
color = RGB::Color.from_rgb_hex(0xFF0000)
|
5
|
+
color = RGB::Color.from_rgb(115, 38, 38)
|
6
|
+
color = RGB::Color.from_fractions(0, 1.0, 0.5) # HSL
|
7
|
+
|
8
|
+
# Supported color manipulations:
|
9
|
+
color.darken(20)
|
10
|
+
color.darken_percent(10)
|
11
|
+
color.darken!(20)
|
12
|
+
color.darken_percent!(10)
|
13
|
+
color.lighten(20)
|
14
|
+
color.lighten_percent(20)
|
15
|
+
color.lighten!(20)
|
16
|
+
color.lighten_percent!(20)
|
17
|
+
color.saturate(20)
|
18
|
+
color.saturate_percent(20)
|
19
|
+
color.saturate!(20)
|
20
|
+
color.saturate_percent!(20)
|
21
|
+
color.desaturate(20)
|
22
|
+
color.desaturate_percent(20)
|
23
|
+
color.desaturate!(20)
|
24
|
+
color.desaturate_percent!(20)
|
25
|
+
|
26
|
+
color.invert!
|
27
|
+
|
28
|
+
# Mixing colors:
|
29
|
+
color.mix(other_color, 20) # Mix 20% of other color into current one
|
30
|
+
color.mix(other_color) # 50% by default
|
31
|
+
color.mix!(other_color, 20)
|
32
|
+
color.mix!(other_color)
|
33
|
+
|
34
|
+
# Also you can adjust color HSL (hue, saturation, and lightness values) manually:
|
35
|
+
color.hue = 0.1
|
36
|
+
color.saturation = 0.2
|
37
|
+
color.lightness = 0.3
|
38
|
+
|
39
|
+
# Supported output formats:
|
40
|
+
color.to_rgb_hex
|
41
|
+
=> "#732626"
|
42
|
+
color.to_hsl
|
43
|
+
=> [0, 1.0, 0.5]
|
44
|
+
color.to_rgb
|
45
|
+
=> [115, 38, 38]
|
46
|
+
|
47
|
+
=end
|
48
|
+
|
49
|
+
module RGB
|
50
|
+
class Color
|
51
|
+
def to_fx
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'xtras/charting.rb'
|
@@ -0,0 +1,247 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Fox
|
3
|
+
module Enhancement
|
4
|
+
module Xtras
|
5
|
+
# Charting constructs. Note that the
|
6
|
+
# rulers have built-in their own labeling, with orientation.
|
7
|
+
module Charting
|
8
|
+
# Box area of drawing interest. This is
|
9
|
+
# more virtual than actual, i.e. no clipping
|
10
|
+
# is performed.
|
11
|
+
class Box
|
12
|
+
include RGB
|
13
|
+
MAX_DOMINANCE = 3
|
14
|
+
NÄHE = [:top_box, :bottom_box, :left_box, :right_box]
|
15
|
+
|
16
|
+
# Name of this box -- we use this in some cases to avoid class polution
|
17
|
+
attr_reader :name
|
18
|
+
|
19
|
+
# coordinate and dimensions of the box
|
20
|
+
attr_accessor :x, :y, :width, :height
|
21
|
+
|
22
|
+
# hints on width and heigt, if meaningful, otherwise nil
|
23
|
+
attr_accessor :hint_width, :hint_height
|
24
|
+
|
25
|
+
# textual / apperance orientation :horizontal, :vertical, :none
|
26
|
+
# placement :top, :bottom, :left, :right
|
27
|
+
attr_accessor :orientation, :placement
|
28
|
+
|
29
|
+
# adjoining boxes
|
30
|
+
attr_accessor :top_box, :bottom_box
|
31
|
+
attr_accessor :left_box, :right_box
|
32
|
+
|
33
|
+
# margins
|
34
|
+
attr_accessor :top_margin, :bottom_margin, :left_margin, :right_margin
|
35
|
+
|
36
|
+
attr_accessor :enabled, :floating
|
37
|
+
|
38
|
+
# dominance rating (must be supplied)
|
39
|
+
attr_accessor :dominance
|
40
|
+
|
41
|
+
# always overide this the default simply renders a box
|
42
|
+
def render dc
|
43
|
+
raise "layout error in #{self.class}" if x.nil? or y.nil? or width.nil? or height.nil?
|
44
|
+
dc.setClipRectangle FXRectangle.new(x,y,width,height)
|
45
|
+
dc.foreground = black
|
46
|
+
dc.drawRectangle x, y, width-1, height-1
|
47
|
+
end
|
48
|
+
|
49
|
+
def enabled? ; enabled ; end
|
50
|
+
def floating? ; floating ; end
|
51
|
+
|
52
|
+
# calc the width and height of this box. Override!
|
53
|
+
def calculate_dimensions
|
54
|
+
self.width ||= (hint_width || 20) #TODO: remove the cheats
|
55
|
+
self.height ||= (hint_height || 10)
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize chart,
|
59
|
+
name: self.class,
|
60
|
+
float: false,
|
61
|
+
enabled: true,
|
62
|
+
dom: 1,
|
63
|
+
orient: :none,
|
64
|
+
placement: :unspecified
|
65
|
+
@chart = chart
|
66
|
+
@name = name
|
67
|
+
@dominance = dom
|
68
|
+
@floating = float
|
69
|
+
@top_margin = @bottom_margin = @left_margin = @right_margin = 0
|
70
|
+
@orientation = orient
|
71
|
+
@enabled = enabled
|
72
|
+
@placement = placement
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
sprintf "<%50s dom=%s xywh=%-17s LRTB=%-14s %s>" % [name,
|
77
|
+
"#{dominance}",
|
78
|
+
"[#{x||'NIL'},#{y||'NIL'},#{width||'NIL'},#{height||'NIL'}]",
|
79
|
+
"[#{left_margin},#{right_margin},#{top_margin},#{bottom_margin}]",
|
80
|
+
"#{floating? ? 'floater' : ''}"
|
81
|
+
]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# The null box represents the side of the container -- the
|
86
|
+
# canvas -- and will simplify layout.
|
87
|
+
class NullBox < Box
|
88
|
+
def initialize chart, **kv
|
89
|
+
super(chart, **kv)
|
90
|
+
@dominance = 0
|
91
|
+
end
|
92
|
+
|
93
|
+
# null box is never rendered.
|
94
|
+
def render dc ; end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Ruler < Box
|
98
|
+
def render dc
|
99
|
+
super
|
100
|
+
# coord is normalized, 0 .. 1
|
101
|
+
Ticks.new(0, 1000) do |t|
|
102
|
+
dc.foreground = black
|
103
|
+
|
104
|
+
t.tick_lambda = ->(coord, value, major) {
|
105
|
+
tick_length = (orientation == :horizontal ? height : width) / (major ? 2 : 4)
|
106
|
+
|
107
|
+
x1 = if orientation == :horizontal
|
108
|
+
x + width * coord
|
109
|
+
elsif orientation == :vertical
|
110
|
+
if placement == :left
|
111
|
+
x + width
|
112
|
+
elsif placement == :right
|
113
|
+
x
|
114
|
+
else
|
115
|
+
raise "unknown placement :#{placement}"
|
116
|
+
end
|
117
|
+
else
|
118
|
+
raise "unknown orientation :#{orientation}"
|
119
|
+
end
|
120
|
+
|
121
|
+
y1 = if orientation == :horizontal
|
122
|
+
if placement == :top
|
123
|
+
y + height
|
124
|
+
elsif placement == :bottom
|
125
|
+
y
|
126
|
+
else
|
127
|
+
raise "unknown placement :#{placement}"
|
128
|
+
end
|
129
|
+
elsif orientation == :vertical
|
130
|
+
y + height * coord
|
131
|
+
else
|
132
|
+
raise "unknown orientation :#{orientation}"
|
133
|
+
end
|
134
|
+
|
135
|
+
x2 = if orientation == :horizontal
|
136
|
+
x1
|
137
|
+
elsif orientation == :vertical
|
138
|
+
if placement == :left
|
139
|
+
x1 - tick_length
|
140
|
+
elsif placement == :right
|
141
|
+
x1 + tick_length
|
142
|
+
else
|
143
|
+
raise "unknown placement :#{placement}"
|
144
|
+
end
|
145
|
+
else
|
146
|
+
raise "unknown orientation :#{orientation}"
|
147
|
+
end
|
148
|
+
|
149
|
+
y2 = if orientation == :horizontal
|
150
|
+
if placement == :top
|
151
|
+
y1 - tick_length
|
152
|
+
elsif placement == :bottom
|
153
|
+
y1 + tick_length
|
154
|
+
else
|
155
|
+
raise "unknown placement :#{placement}"
|
156
|
+
end
|
157
|
+
elsif orientation == :vertical
|
158
|
+
y1
|
159
|
+
else
|
160
|
+
raise "unknown orientation :#{orientation}"
|
161
|
+
end
|
162
|
+
dc.drawLine x1, y1, x2, y2
|
163
|
+
}
|
164
|
+
|
165
|
+
t.tick_label_lambda = ->(coord, label) {}
|
166
|
+
end.compute_ticks
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
def initialize chart, **kv
|
171
|
+
super
|
172
|
+
@dominance = 2
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# For now, we assume that the placement
|
177
|
+
# of PureText boxes shall be above and
|
178
|
+
# below the GraphBox.
|
179
|
+
class PureText < Box
|
180
|
+
def calculate_wh
|
181
|
+
end
|
182
|
+
|
183
|
+
def calculate_dimensions
|
184
|
+
super
|
185
|
+
calculate_wh
|
186
|
+
begin
|
187
|
+
self.x = [top_box.width, bottom_box.width].max / 2 - self.width / 2
|
188
|
+
rescue ArgumentError, NoMethodError, TypeError => e
|
189
|
+
#puts "-->PureText unresolved: #{e}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class Title < PureText
|
195
|
+
end
|
196
|
+
|
197
|
+
class Caption < PureText
|
198
|
+
end
|
199
|
+
|
200
|
+
class Legend < Box
|
201
|
+
# We calculate this on the basis
|
202
|
+
# of our actual content.
|
203
|
+
def calculate_wh
|
204
|
+
self.width = 50 # TODO: we're cheating again.
|
205
|
+
self.height = 30
|
206
|
+
end
|
207
|
+
|
208
|
+
def calculate_dimensions
|
209
|
+
super
|
210
|
+
calculate_wh
|
211
|
+
|
212
|
+
# This is a nasty hard-coding, which will not
|
213
|
+
# allow us to change the location of this box.
|
214
|
+
# Later, we'll want to add that flexibility.
|
215
|
+
self.y = right_box.height / 2 - self.height / 2
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# main charting area.
|
220
|
+
class Graph < Box
|
221
|
+
def calculate_dimensions
|
222
|
+
super
|
223
|
+
begin
|
224
|
+
self.width = right_box.x \
|
225
|
+
- right_box.left_margin \
|
226
|
+
- left_box.x \
|
227
|
+
- left_box.width \
|
228
|
+
+ left_box.right_margin
|
229
|
+
self.height = bottom_box.y \
|
230
|
+
- bottom_box.top_margin \
|
231
|
+
- top_box.y \
|
232
|
+
- top_box.height \
|
233
|
+
+ top_box.bottom_margin
|
234
|
+
rescue NoMethodError, TypeError => e
|
235
|
+
#puts "-->Graph: unresolved: #{e}"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def initialize chart, **kv
|
240
|
+
super
|
241
|
+
@dominance = 3
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|