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,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 = self.instance_block.(self.inst) unless self.instance_block.nil?
44
- self.kinder.each{ |os| os.instance_final_activate unless os.reusable? }
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