eideticrml 0.3.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 +7 -0
- data/Rakefile +55 -0
- data/lib/erml.rb +345 -0
- data/lib/erml_layout_managers.rb +667 -0
- data/lib/erml_rules.rb +104 -0
- data/lib/erml_styles.rb +304 -0
- data/lib/erml_support.rb +105 -0
- data/lib/erml_widget_factories.rb +38 -0
- data/lib/erml_widgets.rb +1895 -0
- data/samples/test10_rich_text.erml +17 -0
- data/samples/test11_table_layout.erml +30 -0
- data/samples/test12_shapes.erml +32 -0
- data/samples/test13_polygons.erml +28 -0
- data/samples/test14_images.erml +19 -0
- data/samples/test15_lines.erml +43 -0
- data/samples/test16_classes.erml +34 -0
- data/samples/test17_rules.erml +24 -0
- data/samples/test18_preformatted_text.erml +9 -0
- data/samples/test19_erb.erml.erb +26 -0
- data/samples/test1_empty_doc.erml +2 -0
- data/samples/test20_haml.erml.haml +20 -0
- data/samples/test21_shift_widgets.erml +47 -0
- data/samples/test22_multipage_flow_layout.erml +40 -0
- data/samples/test23_pageno.erml +17 -0
- data/samples/test24_headers_footers.erml.erb +37 -0
- data/samples/test25_overflow.erml.erb +37 -0
- data/samples/test26_columns.erml.erb +42 -0
- data/samples/test28_landscape.erml.erb +17 -0
- data/samples/test29_pages_up.erml.erb +17 -0
- data/samples/test2_empty_page.erml +6 -0
- data/samples/test30_encodings.erml.haml +35 -0
- data/samples/test3_hello_world.erml +7 -0
- data/samples/test4_two_pages.erml +10 -0
- data/samples/test5_rounded_rect.erml +10 -0
- data/samples/test6_bullets.erml +16 -0
- data/samples/test7_flow_layout.erml +20 -0
- data/samples/test8_vbox_layout.erml +23 -0
- data/samples/test9_hbox_layout.erml +22 -0
- data/samples/testimg.jpg +0 -0
- data/test/test_erml_layout_managers.rb +106 -0
- data/test/test_erml_rules.rb +116 -0
- data/test/test_erml_styles.rb +415 -0
- data/test/test_erml_support.rb +140 -0
- data/test/test_erml_widget_factories.rb +46 -0
- data/test/test_erml_widgets.rb +1235 -0
- data/test/test_helpers.rb +18 -0
- metadata +102 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brent Rowland on 2008-01-16.
|
4
|
+
# Copyright (c) 2008 Eidetic Software. All rights reserved.
|
5
|
+
|
6
|
+
module EideticRML
|
7
|
+
module Widgets
|
8
|
+
class WidgetFactory
|
9
|
+
def initialize
|
10
|
+
@klasses = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def register_widget(tag, klass)
|
14
|
+
@klasses[tag] = klass
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_widget?(tag)
|
18
|
+
!!@klasses[tag]
|
19
|
+
end
|
20
|
+
|
21
|
+
def make_widget(tag, parent, attrs={})
|
22
|
+
attrs['tag'] = tag unless attrs['tag']
|
23
|
+
attrs['class'] = '' if attrs['class'].nil? and attrs[:class].nil?
|
24
|
+
@klasses[tag].new(parent, attrs)
|
25
|
+
end
|
26
|
+
|
27
|
+
@@factories = {}
|
28
|
+
|
29
|
+
def self.for_namespace(namespace)
|
30
|
+
@@factories[namespace]
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.register_factory(namespace, factory)
|
34
|
+
@@factories[namespace] = factory
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/erml_widgets.rb
ADDED
@@ -0,0 +1,1895 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brent Rowland on 2008-01-06.
|
4
|
+
# Copyright (c) 2008 Eidetic Software. All rights reserved.
|
5
|
+
|
6
|
+
require 'erml_support'
|
7
|
+
require 'erml_styles'
|
8
|
+
require 'erml_rules'
|
9
|
+
require 'singleton'
|
10
|
+
require 'erml_widget_factories'
|
11
|
+
|
12
|
+
module EideticRML
|
13
|
+
module Widgets
|
14
|
+
class StdWidgetFactory < WidgetFactory
|
15
|
+
include Singleton
|
16
|
+
|
17
|
+
WidgetFactory.register_factory('std', self.instance)
|
18
|
+
end
|
19
|
+
|
20
|
+
class Widget
|
21
|
+
include Support
|
22
|
+
|
23
|
+
attr_reader :width_pct, :height_pct, :max_width_pct, :max_height_pct
|
24
|
+
attr_accessor :parent, :disabled
|
25
|
+
attr_writer :printed, :visible
|
26
|
+
|
27
|
+
def initialize(parent, attrs={})
|
28
|
+
@parent = parent
|
29
|
+
@display = parent.display
|
30
|
+
parent.children << self if parent.respond_to?(:children)
|
31
|
+
attributes(attrs)
|
32
|
+
@visible = true
|
33
|
+
end
|
34
|
+
|
35
|
+
def clone
|
36
|
+
@clone ||= super
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize_copy(other)
|
40
|
+
@is_clone = true
|
41
|
+
end
|
42
|
+
|
43
|
+
def attributes(attrs)
|
44
|
+
attrs = attrs.inject({}) { |m, kv| m[kv.first.to_s.sub(/^class$/,'klass')] = kv.last; m } # stringify keys
|
45
|
+
pre_keys, post_keys = attributes_first & attrs.keys, attributes_last & attrs.keys # keys are sorted same as attributes_first
|
46
|
+
keys = attrs.keys - pre_keys - post_keys
|
47
|
+
pre_keys.each { |key| attribute(key, attrs[key]) }
|
48
|
+
keys.each { |key| attribute(key, attrs[key]) }
|
49
|
+
post_keys.each { |key| attribute(key, attrs[key]) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def align(value=nil)
|
53
|
+
return @align if value.nil?
|
54
|
+
@align = value.to_sym if [:top, :right, :bottom, :left].include?(value.to_sym)
|
55
|
+
end
|
56
|
+
|
57
|
+
def position(value=nil)
|
58
|
+
return @position || :static if value.nil?
|
59
|
+
@position = value.to_sym if [:static, :relative, :absolute].include?(value.to_sym)
|
60
|
+
end
|
61
|
+
|
62
|
+
def tag(value=nil)
|
63
|
+
return @tag if value.nil?
|
64
|
+
@tag = $1.freeze if value.to_s =~ /^(\w+)$/
|
65
|
+
@path = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def id(value=nil)
|
69
|
+
return @id if value.nil?
|
70
|
+
if value.to_s =~ /^(\w+)$/
|
71
|
+
@id = $1.freeze
|
72
|
+
root.widgets[@id] = self
|
73
|
+
end
|
74
|
+
@path = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def klass(value=nil)
|
78
|
+
return @klass if value.nil?
|
79
|
+
@klass = $1.freeze if value.to_s =~ /^\s*(\w+(\s+\w+)*)\s*$/
|
80
|
+
@path = nil
|
81
|
+
return if parent.nil?
|
82
|
+
attributes(root.rules.matching(path).inject({}) { |attrs, rule| attrs.update(rule.attrs) })
|
83
|
+
end
|
84
|
+
|
85
|
+
def selector_tag
|
86
|
+
value = (tag || '').dup
|
87
|
+
value << '#' << id unless id.nil?
|
88
|
+
value << '.' << klass.split(/\s/).join('.') unless klass.nil?
|
89
|
+
value
|
90
|
+
end
|
91
|
+
|
92
|
+
def path
|
93
|
+
@path ||= (parent.nil? ? selector_tag : parent.path.dup << '/' << selector_tag).freeze
|
94
|
+
end
|
95
|
+
|
96
|
+
def left(value=nil, units=nil)
|
97
|
+
return rel_x(shifted_x(@left || ((@right.nil? or width.nil?) ? nil : @right - width))) if value.nil?
|
98
|
+
return to_units(value, left) if value.is_a?(Symbol)
|
99
|
+
@position = :relative if position == :static and value.respond_to?(:to_str)
|
100
|
+
@left = parse_measurement_pts(value, units || self.units)
|
101
|
+
@left = parent.width + @left if @left < 0
|
102
|
+
@width = @right - @left unless @right.nil?
|
103
|
+
end
|
104
|
+
|
105
|
+
def top(value=nil, units=nil)
|
106
|
+
return rel_y(shifted_y(@top || ((@bottom.nil? or height.nil?) ? nil : @bottom - height))) if value.nil?
|
107
|
+
return to_units(value, top) if value.is_a?(Symbol)
|
108
|
+
@position = :relative if position == :static and value.respond_to?(:to_str)
|
109
|
+
@top = parse_measurement_pts(value, units || self.units)
|
110
|
+
@top = parent.height + @top if @top < 0
|
111
|
+
@height = @bottom - @top unless @bottom.nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
def right(value=nil, units=nil)
|
115
|
+
return rel_y(shifted_x(@right || ((@left.nil? or width.nil?) ? nil : @left + width))) if value.nil?
|
116
|
+
return to_units(value, right) if value.is_a?(Symbol)
|
117
|
+
@position = :relative if position == :static and value.respond_to?(:to_str)
|
118
|
+
@right = parse_measurement_pts(value, units || self.units)
|
119
|
+
@right = parent.width + @right if @right <= 0
|
120
|
+
@width = @right - @left unless @left.nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
def bottom(value=nil, units=nil)
|
124
|
+
return rel_y(shifted_y(@bottom || ((@top.nil? or height.nil?) ? nil : @top + height))) if value.nil?
|
125
|
+
return to_units(value, bottom) if value.is_a?(Symbol)
|
126
|
+
@position = :relative if position == :static and value.respond_to?(:to_str)
|
127
|
+
@bottom = parse_measurement_pts(value, units || self.units)
|
128
|
+
@bottom = parent.height + @bottom if @bottom <= 0
|
129
|
+
@height = @bottom - @top unless @top.nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
def shift(value=nil, units=nil)
|
133
|
+
return [shift_x(units || :pt), shift_y(units || :pt)] if value.nil?
|
134
|
+
if value.respond_to?(:to_str)
|
135
|
+
x, y = value.to_s.split(',', 2)
|
136
|
+
else
|
137
|
+
x, y = Array(value)
|
138
|
+
end
|
139
|
+
@shift_x, @shift_y = parse_measurement_pts(x, units || self.units), parse_measurement_pts(y, units || self.units)
|
140
|
+
end
|
141
|
+
|
142
|
+
def has_height?
|
143
|
+
@height and !@height_pct
|
144
|
+
end
|
145
|
+
|
146
|
+
def has_width?
|
147
|
+
@width and !@width_pct
|
148
|
+
end
|
149
|
+
|
150
|
+
def preferred_width(writer, units=:pt)
|
151
|
+
@width ? to_units(units, @width) : nil
|
152
|
+
end
|
153
|
+
|
154
|
+
def preferred_height(writer, units=:pt)
|
155
|
+
@height ? to_units(units, @height) : nil
|
156
|
+
end
|
157
|
+
|
158
|
+
def width(value=nil, units=nil)
|
159
|
+
return @width_pct ? @width_pct * parent.content_width : @width if value.nil?
|
160
|
+
return to_units(value, width) if value.is_a?(Symbol)
|
161
|
+
if value =~ /(\d+(\.\d+)?)%/
|
162
|
+
@width_pct = $1.to_f.quo(100)
|
163
|
+
# @width = @width_pct * parent.content_width
|
164
|
+
@width = nil
|
165
|
+
elsif value.to_s =~ /^[+-]/
|
166
|
+
@width = parent.content_width + parse_measurement_pts(value, units || self.units)
|
167
|
+
@width_pct = nil
|
168
|
+
else
|
169
|
+
@width = parse_measurement_pts(value, units || self.units)
|
170
|
+
@width_pct = nil
|
171
|
+
end
|
172
|
+
@right = nil unless @left.nil?
|
173
|
+
width_set
|
174
|
+
end
|
175
|
+
|
176
|
+
def height(value=nil, units=nil)
|
177
|
+
return @height_pct ? @height_pct * parent.content_height : @height if value.nil?
|
178
|
+
return to_units(value, height) if value.is_a?(Symbol)
|
179
|
+
if value =~ /(\d+(\.\d+)?)%/
|
180
|
+
@height_pct = $1.to_f.quo(100)
|
181
|
+
@height = @height_pct * parent.content_height
|
182
|
+
elsif value.to_s =~ /^[+-]/
|
183
|
+
@height = parent.content_height + parse_measurement_pts(value, units || self.units)
|
184
|
+
@height_pct = nil
|
185
|
+
else
|
186
|
+
@height = parse_measurement_pts(value, units || self.units)
|
187
|
+
@height_pct = nil
|
188
|
+
end
|
189
|
+
@bottom = nil unless @top.nil?
|
190
|
+
height_set
|
191
|
+
end
|
192
|
+
|
193
|
+
def max_width(value=nil, units=nil)
|
194
|
+
return @max_width_pct ? @max_width_pct * parent.content_width : @max_width if value.nil?
|
195
|
+
return to_units(value, max_width) if value.is_a?(Symbol)
|
196
|
+
if value =~ /(\d+(\.\d+)?)%/
|
197
|
+
@max_width_pct = $1.to_f.quo(100)
|
198
|
+
@max_width = @max_width_pct * parent.content_width
|
199
|
+
elsif value.to_s =~ /^[+-]/
|
200
|
+
@max_width = parent.content_width + parse_measurement_pts(value, units || self.units)
|
201
|
+
@max_width_pct = nil
|
202
|
+
else
|
203
|
+
@max_width = parse_measurement_pts(value, units || self.units)
|
204
|
+
@max_width_pct = nil
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def max_height(value=nil, units=nil)
|
209
|
+
return @max_height_pct ? @max_height_pct * parent.content_height : @max_height if value.nil?
|
210
|
+
return to_units(value, max_height) if value.is_a?(Symbol)
|
211
|
+
if value =~ /(\d+(\.\d+)?)%/
|
212
|
+
@max_height_pct = $1.to_f.quo(100)
|
213
|
+
@max_height = @max_height_pct * parent.content_height
|
214
|
+
elsif value.to_s =~ /^[+-]/
|
215
|
+
@max_height = parent.content_height + parse_measurement_pts(value, units || self.units)
|
216
|
+
@max_height_pct = nil
|
217
|
+
else
|
218
|
+
@max_height = parse_measurement_pts(value, units || self.units)
|
219
|
+
@hmax_height_pct = nil
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def max_content_height
|
224
|
+
max_height_avail - non_content_height
|
225
|
+
end
|
226
|
+
|
227
|
+
def max_height_avail
|
228
|
+
height || parent.max_content_height - ((top || parent.content_top) - parent.content_top)
|
229
|
+
end
|
230
|
+
|
231
|
+
def content_top(units=:pt)
|
232
|
+
to_units(units, top + margin_top + padding_top)
|
233
|
+
end
|
234
|
+
|
235
|
+
def content_right(units=:pt)
|
236
|
+
to_units(units, right - margin_right - padding_right)
|
237
|
+
end
|
238
|
+
|
239
|
+
def content_bottom(units=:pt)
|
240
|
+
to_units(units, bottom - margin_bottom - padding_bottom)
|
241
|
+
end
|
242
|
+
|
243
|
+
def content_left(units=:pt)
|
244
|
+
to_units(units, left + margin_left + padding_left)
|
245
|
+
end
|
246
|
+
|
247
|
+
def content_height(units=:pt)
|
248
|
+
to_units(units, (height || 0) - non_content_height)
|
249
|
+
end
|
250
|
+
|
251
|
+
def content_width(units=:pt)
|
252
|
+
to_units(units, (width || 0) - non_content_width)
|
253
|
+
end
|
254
|
+
|
255
|
+
def non_content_height
|
256
|
+
margin_top + padding_top + padding_bottom + margin_bottom
|
257
|
+
end
|
258
|
+
|
259
|
+
def non_content_width
|
260
|
+
margin_left + padding_left + padding_right + margin_right
|
261
|
+
end
|
262
|
+
|
263
|
+
def before_layout
|
264
|
+
@orig_width, @orig_height = @width, @height
|
265
|
+
end
|
266
|
+
|
267
|
+
def layout_widget(writer)
|
268
|
+
# override this method
|
269
|
+
end
|
270
|
+
|
271
|
+
def after_layout
|
272
|
+
# override this method
|
273
|
+
end
|
274
|
+
|
275
|
+
def units(value=nil)
|
276
|
+
# inherited
|
277
|
+
return @units || parent.units if value.nil?
|
278
|
+
@units = value.to_sym if EideticPDF::UNIT_CONVERSION[value.to_sym]
|
279
|
+
end
|
280
|
+
|
281
|
+
def border(value=nil)
|
282
|
+
return @border if value.nil?
|
283
|
+
@border = pen_style_for(value)
|
284
|
+
@border_top = @border_right = @border_bottom = @border_left = nil
|
285
|
+
end
|
286
|
+
|
287
|
+
def border_top(value=nil)
|
288
|
+
return @border_top || @border if value.nil?
|
289
|
+
@border_top = pen_style_for(value)
|
290
|
+
end
|
291
|
+
|
292
|
+
def border_right(value=nil)
|
293
|
+
return @border_right || @border if value.nil?
|
294
|
+
@border_right = pen_style_for(value)
|
295
|
+
end
|
296
|
+
|
297
|
+
def border_bottom(value=nil)
|
298
|
+
return @border_bottom || @border if value.nil?
|
299
|
+
@border_bottom = pen_style_for(value)
|
300
|
+
end
|
301
|
+
|
302
|
+
def border_left(value=nil)
|
303
|
+
return @border_left || @border if value.nil?
|
304
|
+
@border_left = pen_style_for(value)
|
305
|
+
end
|
306
|
+
|
307
|
+
def fill(value=nil)
|
308
|
+
return @fill if value.nil?
|
309
|
+
@fill = brush_style_for(value)
|
310
|
+
end
|
311
|
+
|
312
|
+
def margin_top(value=nil)
|
313
|
+
return @margin_top || 0 if value.nil?
|
314
|
+
return to_units(value, margin_top) if value.is_a?(Symbol)
|
315
|
+
@margin_top = parse_measurement_pts(value, units)
|
316
|
+
end
|
317
|
+
|
318
|
+
def margin_right(value=nil)
|
319
|
+
return @margin_right || 0 if value.nil?
|
320
|
+
return to_units(value, margin_right) if value.is_a?(Symbol)
|
321
|
+
@margin_right = parse_measurement_pts(value, units)
|
322
|
+
end
|
323
|
+
|
324
|
+
def margin_bottom(value=nil)
|
325
|
+
return @margin_bottom || 0 if value.nil?
|
326
|
+
return to_units(value, margin_bottom) if value.is_a?(Symbol)
|
327
|
+
@margin_bottom = parse_measurement_pts(value, units)
|
328
|
+
end
|
329
|
+
|
330
|
+
def margin_left(value=nil)
|
331
|
+
return @margin_left || 0 if value.nil?
|
332
|
+
return to_units(value, margin_left) if value.is_a?(Symbol)
|
333
|
+
@margin_left = parse_measurement_pts(value, units)
|
334
|
+
end
|
335
|
+
|
336
|
+
def margin(value=nil)
|
337
|
+
return [margin_top, margin_right, margin_bottom, margin_left] if value.nil?
|
338
|
+
return [margin_top(value), margin_right(value), margin_bottom(value), margin_left(value)] if value.is_a?(Symbol)
|
339
|
+
if value.respond_to?(:to_str)
|
340
|
+
value = value.split(',').map do |n|
|
341
|
+
parse_measurement_pts(n, units)
|
342
|
+
end
|
343
|
+
else
|
344
|
+
value = Array(value).map { |m| from_units(units, m) }
|
345
|
+
end
|
346
|
+
m = case value.size
|
347
|
+
when 4 then value
|
348
|
+
when 2 then value * 2
|
349
|
+
when 1 then value * 4
|
350
|
+
else nil
|
351
|
+
end
|
352
|
+
@margin_top, @margin_right, @margin_bottom, @margin_left = m unless m.nil?
|
353
|
+
end
|
354
|
+
|
355
|
+
def default_padding_top
|
356
|
+
0
|
357
|
+
end
|
358
|
+
|
359
|
+
def default_padding_right
|
360
|
+
0
|
361
|
+
end
|
362
|
+
|
363
|
+
def default_padding_bottom
|
364
|
+
0
|
365
|
+
end
|
366
|
+
|
367
|
+
def default_padding_left
|
368
|
+
0
|
369
|
+
end
|
370
|
+
|
371
|
+
def padding_top(value=nil)
|
372
|
+
return @padding_top || default_padding_top if value.nil?
|
373
|
+
return to_units(value, padding_top) if value.is_a?(Symbol)
|
374
|
+
@padding_top = parse_measurement_pts(value, units)
|
375
|
+
end
|
376
|
+
|
377
|
+
def padding_right(value=nil)
|
378
|
+
return @padding_right || default_padding_right if value.nil?
|
379
|
+
return to_units(value, padding_right) if value.is_a?(Symbol)
|
380
|
+
@padding_right = parse_measurement_pts(value, units)
|
381
|
+
end
|
382
|
+
|
383
|
+
def padding_bottom(value=nil)
|
384
|
+
return @padding_bottom || default_padding_bottom if value.nil?
|
385
|
+
return to_units(value, padding_bottom) if value.is_a?(Symbol)
|
386
|
+
@padding_bottom = parse_measurement_pts(value, units)
|
387
|
+
end
|
388
|
+
|
389
|
+
def padding_left(value=nil)
|
390
|
+
return @padding_left || default_padding_left if value.nil?
|
391
|
+
return to_units(value, padding_left) if value.is_a?(Symbol)
|
392
|
+
@padding_left = parse_measurement_pts(value, units)
|
393
|
+
end
|
394
|
+
|
395
|
+
def padding(value=nil)
|
396
|
+
return [padding_top, padding_right, padding_bottom, padding_left] if value.nil?
|
397
|
+
return [padding_top(value), padding_right(value), padding_bottom(value), padding_left(value)] if value.is_a?(Symbol)
|
398
|
+
if value.respond_to?(:to_str)
|
399
|
+
value = value.split(',').map do |n|
|
400
|
+
parse_measurement_pts(n, units)
|
401
|
+
end
|
402
|
+
else
|
403
|
+
value = Array(value).map { |p| from_units(units, p) }
|
404
|
+
end
|
405
|
+
p = case value.size
|
406
|
+
when 4 then value
|
407
|
+
when 2 then value * 2
|
408
|
+
when 1 then value * 4
|
409
|
+
else nil
|
410
|
+
end
|
411
|
+
@padding_top, @padding_right, @padding_bottom, @padding_left = p unless p.nil?
|
412
|
+
end
|
413
|
+
|
414
|
+
def font(value=nil)
|
415
|
+
# inherited
|
416
|
+
return @font || parent.font if value.nil?
|
417
|
+
return @font = font.clone if value == :copy
|
418
|
+
@font = font_style_for(value)
|
419
|
+
end
|
420
|
+
|
421
|
+
def font_color(value=nil)
|
422
|
+
return font.color if value.nil?
|
423
|
+
font(:copy).color(value)
|
424
|
+
end
|
425
|
+
|
426
|
+
def font_size(value=nil)
|
427
|
+
return font.size if value.nil?
|
428
|
+
font(:copy).size(value)
|
429
|
+
end
|
430
|
+
|
431
|
+
def font_style(value=nil)
|
432
|
+
return font.style if value.nil?
|
433
|
+
@font = font.clone
|
434
|
+
@font.style(value)
|
435
|
+
end
|
436
|
+
|
437
|
+
def font_weight(value=nil)
|
438
|
+
return font.weight if value.nil?
|
439
|
+
@font = font.clone
|
440
|
+
@font.weight(value)
|
441
|
+
end
|
442
|
+
|
443
|
+
def print(writer)
|
444
|
+
# $stderr.puts "<<<try printing #{object_id} (#{tag}) visible: #{visible}"
|
445
|
+
return if visible == false
|
446
|
+
return if disabled
|
447
|
+
# $stderr.puts "print #{tag} { left = #{left}, top = #{top}}"
|
448
|
+
before_print(writer)
|
449
|
+
if @rotate.nil?
|
450
|
+
paint_background(writer)
|
451
|
+
draw_content(writer)
|
452
|
+
draw_border(writer)
|
453
|
+
else
|
454
|
+
writer.rotate(rotate, origin_x, origin_y) do
|
455
|
+
paint_background(writer)
|
456
|
+
draw_content(writer)
|
457
|
+
draw_border(writer)
|
458
|
+
end
|
459
|
+
end
|
460
|
+
@printed = true
|
461
|
+
# $stderr.puts ">>>printed #{object_id} (#{tag})"
|
462
|
+
@width = @orig_width if @orig_width
|
463
|
+
@height = @orig_height if @orig_height
|
464
|
+
rescue Exception => e
|
465
|
+
raise RuntimeError, e.message + "\nError printing #{path}.", e.backtrace
|
466
|
+
end
|
467
|
+
|
468
|
+
def printed
|
469
|
+
@printed or @disabled
|
470
|
+
end
|
471
|
+
|
472
|
+
def root
|
473
|
+
parent.nil? ? self : parent.root
|
474
|
+
end
|
475
|
+
|
476
|
+
def root_page
|
477
|
+
parent.root_page
|
478
|
+
end
|
479
|
+
|
480
|
+
def display(value=nil)
|
481
|
+
return @display || :once if value.nil?
|
482
|
+
@display = value.to_sym if [:once, :always, :first, :succeeding, :even, :odd].include?(value.to_sym)
|
483
|
+
end
|
484
|
+
|
485
|
+
def display_for_page(document_page_no, section_page_no)
|
486
|
+
# puts "display_for_page: #{display.inspect}"
|
487
|
+
case display
|
488
|
+
when :always then true
|
489
|
+
when :first then section_page_no == 1
|
490
|
+
when :succeeding then section_page_no > 1
|
491
|
+
when :even then document_page_no.even?
|
492
|
+
when :odd then document_page_no.odd?
|
493
|
+
else false
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
def colspan(value=nil)
|
498
|
+
return @colspan || 1 if value.nil?
|
499
|
+
@colspan = value.to_i if value.to_i >= 1
|
500
|
+
end
|
501
|
+
|
502
|
+
def rowspan(value=nil)
|
503
|
+
return @rowspan || 1 if value.nil?
|
504
|
+
@rowspan = value.to_i if value.to_i >= 1
|
505
|
+
end
|
506
|
+
|
507
|
+
def origin_x(value=nil)
|
508
|
+
if value.nil?
|
509
|
+
case @origin_x
|
510
|
+
when 'left' then left
|
511
|
+
when 'center' then (left + right).quo(2)
|
512
|
+
when 'right' then right
|
513
|
+
else left
|
514
|
+
end
|
515
|
+
else
|
516
|
+
@origin_x = value.strip
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
def origin_y(value=nil)
|
521
|
+
if value.nil?
|
522
|
+
case @origin_y
|
523
|
+
when 'top' then top
|
524
|
+
when 'middle' then (top + bottom).quo(2)
|
525
|
+
when 'bottom' then bottom
|
526
|
+
else top
|
527
|
+
end
|
528
|
+
else
|
529
|
+
@origin_y = value.strip
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
def rotate(value=nil)
|
534
|
+
return @rotate if value.nil?
|
535
|
+
@rotate = value.to_f
|
536
|
+
end
|
537
|
+
|
538
|
+
def z_index(value=nil)
|
539
|
+
return @z_index || 0 if value.nil?
|
540
|
+
@z_index = value.to_i
|
541
|
+
end
|
542
|
+
|
543
|
+
def visible(bounds=nil)
|
544
|
+
return @visible if bounds.nil?
|
545
|
+
return 0 if left.nil? or top.nil? or right.nil? or bottom.nil?
|
546
|
+
(left >= bounds.left and top >= bounds.top and right <= bounds.right and bottom <= bounds.bottom) ? 1 : 0
|
547
|
+
end
|
548
|
+
|
549
|
+
# def postpone
|
550
|
+
# @visible = false
|
551
|
+
# @postponed ||= 0
|
552
|
+
# @postponed += 1
|
553
|
+
# @disabled = true if @postponed > 1
|
554
|
+
# end
|
555
|
+
|
556
|
+
def leaf?
|
557
|
+
true
|
558
|
+
end
|
559
|
+
|
560
|
+
def leaves
|
561
|
+
leaf? ? 1 : 0
|
562
|
+
end
|
563
|
+
|
564
|
+
protected
|
565
|
+
def attribute(id, value)
|
566
|
+
keys = id.to_s.split('.', 2)
|
567
|
+
if keys.size == 1
|
568
|
+
self.send(keys[0], value)
|
569
|
+
else
|
570
|
+
self.send(keys[0], :copy).send(keys[1], value)
|
571
|
+
end
|
572
|
+
rescue NoMethodError => e
|
573
|
+
raise ArgumentError, "Unknown attribute #{id}", e.backtrace
|
574
|
+
end
|
575
|
+
|
576
|
+
def attributes_first
|
577
|
+
@@attributes_first ||= %w(id tag class units position
|
578
|
+
left top width height right bottom
|
579
|
+
margin margin_top margin_right margin_bottom margin_left
|
580
|
+
padding padding_top padding_right padding_bottom padding_left
|
581
|
+
font border fill).freeze
|
582
|
+
end
|
583
|
+
|
584
|
+
def attributes_last
|
585
|
+
@@attributes_last ||= %w(text).freeze
|
586
|
+
end
|
587
|
+
|
588
|
+
def before_print(writer)
|
589
|
+
# override this method
|
590
|
+
end
|
591
|
+
|
592
|
+
def brush_style_for(id)
|
593
|
+
bs = root.styles.for_id(id) || root.styles.for_id("brush_#{id}")
|
594
|
+
bs = root.styles.add('brush', :id => "brush_#{id}", :color => id) if bs.nil? and EideticPDF::PdfK::NAMED_COLORS[id]
|
595
|
+
raise ArgumentError, "Brush Style #{id} not found." unless bs.is_a?(Styles::BrushStyle)
|
596
|
+
bs
|
597
|
+
end
|
598
|
+
|
599
|
+
def draw_border(writer, pen=nil)
|
600
|
+
if pen
|
601
|
+
pen.apply(writer)
|
602
|
+
writer.rectangle(left + margin_left, top + margin_top,
|
603
|
+
width - margin_left - margin_right, height - margin_top - margin_bottom)
|
604
|
+
elsif [@border_top, @border_right, @border_bottom, @border_left].all? { |b| b.nil? }
|
605
|
+
unless @border.nil?
|
606
|
+
@border.apply(writer)
|
607
|
+
writer.rectangle(left + margin_left, top + margin_top,
|
608
|
+
width - margin_left - margin_right, height - margin_top - margin_bottom)
|
609
|
+
end
|
610
|
+
else
|
611
|
+
unless @border_top.nil?
|
612
|
+
@border_top.apply(writer)
|
613
|
+
writer.move_to(left + margin_left, top + margin_top) # top left
|
614
|
+
writer.line_to(right - margin_right, top + margin_top) # top right
|
615
|
+
end
|
616
|
+
unless @border_right.nil?
|
617
|
+
@border_right.apply(writer)
|
618
|
+
writer.move_to(right - margin_right, top + margin_top) # top right
|
619
|
+
writer.line_to(right - margin_right, bottom - margin_bottom) # bottom right
|
620
|
+
end
|
621
|
+
unless @border_bottom.nil?
|
622
|
+
@border_bottom.apply(writer)
|
623
|
+
writer.move_to(right - margin_right, bottom - margin_bottom) # bottom right
|
624
|
+
writer.line_to(left + margin_left, bottom - margin_bottom) # bottom left
|
625
|
+
end
|
626
|
+
unless @border_left.nil?
|
627
|
+
@border_left.apply(writer)
|
628
|
+
writer.move_to(left + margin_left, bottom - margin_bottom) # bottom left
|
629
|
+
writer.line_to(left + margin_left, top + margin_top) # top left
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
def draw_content(writer)
|
635
|
+
# override this method
|
636
|
+
end
|
637
|
+
|
638
|
+
def font_style_for(id)
|
639
|
+
fs = root.styles.for_id(id)
|
640
|
+
raise ArgumentError, "Font Style #{id} not found." unless fs.is_a?(Styles::FontStyle)
|
641
|
+
fs
|
642
|
+
end
|
643
|
+
|
644
|
+
def height_set
|
645
|
+
# override this callback
|
646
|
+
end
|
647
|
+
|
648
|
+
def paint_background(writer)
|
649
|
+
unless @fill.nil?
|
650
|
+
@fill.apply(writer)
|
651
|
+
writer.rectangle(left + margin_left, top + margin_top,
|
652
|
+
width - margin_left - margin_right, height - margin_top - margin_bottom,
|
653
|
+
:fill => true, :border => false)
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
def pen_style_for(id)
|
658
|
+
ps = root.styles.for_id(id) || root.styles.for_id("pen_#{id}")
|
659
|
+
ps = root.styles.add('pen', :id => "pen_#{id}", :pattern => 'solid', :color => id) if ps.nil? and EideticPDF::PdfK::NAMED_COLORS[id]
|
660
|
+
raise ArgumentError, "Pen Style #{id} not found." unless ps.is_a?(Styles::PenStyle)
|
661
|
+
ps
|
662
|
+
end
|
663
|
+
|
664
|
+
def shift_x(units=:pt)
|
665
|
+
to_units(units, @shift_x || 0)
|
666
|
+
end
|
667
|
+
|
668
|
+
def shift_y(units=:pt)
|
669
|
+
to_units(units, @shift_y || 0)
|
670
|
+
end
|
671
|
+
|
672
|
+
def shifted_x(value)
|
673
|
+
value.nil? ? nil : shift_x + value
|
674
|
+
end
|
675
|
+
|
676
|
+
def shifted_y(value)
|
677
|
+
value.nil? ? nil : shift_y + value
|
678
|
+
end
|
679
|
+
|
680
|
+
def rel_x(value)
|
681
|
+
value.nil? ? nil : (position == :relative ? parent.left + value : value)
|
682
|
+
end
|
683
|
+
|
684
|
+
def rel_y(value)
|
685
|
+
value.nil? ? nil : (position == :relative ? parent.top + value : value)
|
686
|
+
end
|
687
|
+
|
688
|
+
def widget_for(id)
|
689
|
+
root.widgets[id]
|
690
|
+
end
|
691
|
+
|
692
|
+
def width_set
|
693
|
+
# override this callback
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
module HasLocation
|
698
|
+
def x(value=nil)
|
699
|
+
return @x if value.nil?
|
700
|
+
return to_units(value, @x) if value.is_a?(Symbol)
|
701
|
+
@position = :relative if position == :static and value.respond_to?(:to_str)
|
702
|
+
@x = parse_measurement_pts(value, units)
|
703
|
+
@x = parent.width - parent.margin_right + @x if @x < 0
|
704
|
+
end
|
705
|
+
|
706
|
+
def y(value=nil)
|
707
|
+
return @y if value.nil?
|
708
|
+
return to_units(value, @y) if value.is_a?(Symbol)
|
709
|
+
@position = :relative if position == :static and value.respond_to?(:to_str)
|
710
|
+
@y = parse_measurement_pts(value, units)
|
711
|
+
@y = parent.height - parent.margin_bottom + @y if @y < 0
|
712
|
+
end
|
713
|
+
end
|
714
|
+
|
715
|
+
module Shape
|
716
|
+
include HasLocation
|
717
|
+
|
718
|
+
protected
|
719
|
+
def draw_border(writer)
|
720
|
+
# suppress default behavior
|
721
|
+
debug_pen_style = "debug_#{tag}_border"
|
722
|
+
if root.styles.for_id(debug_pen_style)
|
723
|
+
super(writer, pen_style_for(debug_pen_style))
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
def paint_background(writer)
|
728
|
+
# suppress default behavior
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
class Arc < Widget
|
733
|
+
StdWidgetFactory.instance.register_widget('arc', self)
|
734
|
+
|
735
|
+
include Shape
|
736
|
+
|
737
|
+
def r(value=nil)
|
738
|
+
# TODO
|
739
|
+
end
|
740
|
+
|
741
|
+
def start_angle(value=nil)
|
742
|
+
# TODO
|
743
|
+
end
|
744
|
+
|
745
|
+
def end_angle(value=nil)
|
746
|
+
# TODO
|
747
|
+
end
|
748
|
+
|
749
|
+
protected
|
750
|
+
def draw_content(writer)
|
751
|
+
# TODO
|
752
|
+
end
|
753
|
+
end
|
754
|
+
|
755
|
+
class Arch < Arc
|
756
|
+
StdWidgetFactory.instance.register_widget('arc', self)
|
757
|
+
|
758
|
+
undef_method :r
|
759
|
+
|
760
|
+
def r1(value=nil)
|
761
|
+
# TODO
|
762
|
+
end
|
763
|
+
|
764
|
+
def r2(value=nil)
|
765
|
+
# TODO
|
766
|
+
end
|
767
|
+
|
768
|
+
protected
|
769
|
+
def draw_content(writer)
|
770
|
+
# TODO
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
class Image < Widget
|
775
|
+
StdWidgetFactory.instance.register_widget('image', self)
|
776
|
+
|
777
|
+
def has_height?
|
778
|
+
true
|
779
|
+
end
|
780
|
+
|
781
|
+
def has_width?
|
782
|
+
true
|
783
|
+
end
|
784
|
+
|
785
|
+
def preferred_width(writer, units=:pt)
|
786
|
+
if @width.nil? and @height
|
787
|
+
w = @height * image(writer).width.quo(image(writer).height)
|
788
|
+
else
|
789
|
+
w = @width || image(writer).width
|
790
|
+
end
|
791
|
+
to_units(units, w)
|
792
|
+
end
|
793
|
+
|
794
|
+
def preferred_height(writer, units=:pt)
|
795
|
+
if @height.nil? and @width
|
796
|
+
# $stderr.puts "path A, width = #{@width}"
|
797
|
+
h = @width * image(writer).height.quo(image(writer).width)
|
798
|
+
else
|
799
|
+
# $stderr.puts "path B"
|
800
|
+
h = @height || image(writer).height
|
801
|
+
end
|
802
|
+
# $stderr.puts "h = #{h}"
|
803
|
+
to_units(units, h)
|
804
|
+
end
|
805
|
+
|
806
|
+
def url(value=nil)
|
807
|
+
return @url if value.nil?
|
808
|
+
@url = value.to_s
|
809
|
+
end
|
810
|
+
|
811
|
+
protected
|
812
|
+
def draw_content(writer)
|
813
|
+
# $stderr.puts "print image: #{url}"
|
814
|
+
writer.print_image_file(load_image(writer), left, top, width, height)
|
815
|
+
end
|
816
|
+
|
817
|
+
def image(writer)
|
818
|
+
load_image(writer) if @image.nil?
|
819
|
+
@image
|
820
|
+
end
|
821
|
+
|
822
|
+
def load_image(writer)
|
823
|
+
raise Exception, "Image url must be specified." if url.nil?
|
824
|
+
@image, @name = writer.load_image(url, stream) if @image.nil?
|
825
|
+
url
|
826
|
+
end
|
827
|
+
|
828
|
+
def stream
|
829
|
+
@stream ||= open(url, EideticPDF::ImageReadMode) { |io| io.read }
|
830
|
+
end
|
831
|
+
end
|
832
|
+
|
833
|
+
class Line < Widget
|
834
|
+
StdWidgetFactory.instance.register_widget('line', self)
|
835
|
+
|
836
|
+
include Shape
|
837
|
+
|
838
|
+
def angle(value=nil)
|
839
|
+
return @angle || 0 if value.nil?
|
840
|
+
@angle = value.to_f
|
841
|
+
end
|
842
|
+
|
843
|
+
def length(value=nil)
|
844
|
+
# return @length || Math::sqrt(content_width ** 2 + content_height ** 2) if value.nil?
|
845
|
+
return @length || calc_length if value.nil?
|
846
|
+
return to_units(value, length) if value.is_a?(Symbol)
|
847
|
+
@length = parse_measurement_pts(value, units)
|
848
|
+
end
|
849
|
+
|
850
|
+
def preferred_width(writer, units=:pt)
|
851
|
+
w = @width || preferred_content_width + non_content_width
|
852
|
+
to_units(units, w)
|
853
|
+
end
|
854
|
+
|
855
|
+
def preferred_height(writer, units=:pt)
|
856
|
+
h = @height || preferred_content_height + non_content_height
|
857
|
+
to_units(units, h)
|
858
|
+
end
|
859
|
+
|
860
|
+
def style(value=nil)
|
861
|
+
return @style || pen_style_for('solid') if value.nil?
|
862
|
+
@style = pen_style_for(value)
|
863
|
+
end
|
864
|
+
|
865
|
+
protected
|
866
|
+
def calc_length
|
867
|
+
return 0 if width.nil? or height.nil?
|
868
|
+
l = Math::sqrt(content_width ** 2 + content_height ** 2)
|
869
|
+
w = Math::cos(angle.degrees) * l
|
870
|
+
h = Math::sin(angle.degrees) * l
|
871
|
+
if w > content_width
|
872
|
+
l *= content_width.quo(w)
|
873
|
+
elsif h > content_height
|
874
|
+
l *= content_height.quo(h)
|
875
|
+
end
|
876
|
+
l
|
877
|
+
end
|
878
|
+
|
879
|
+
def draw_content(writer)
|
880
|
+
# puts "cw: #{content_width}, ch: #{content_height}"
|
881
|
+
style.apply(writer)
|
882
|
+
if position == :absolute
|
883
|
+
raise Exception, "x and y must be set." unless @x and @y
|
884
|
+
writer.line(@x, @y, angle, length)
|
885
|
+
elsif position == :relative
|
886
|
+
raise Exception, "x and y must be set." unless @x and @y
|
887
|
+
writer.line(parent.content_left + @x, parent.content_top + @y, angle, length)
|
888
|
+
else
|
889
|
+
@x, @y = origin_for_quadrant(quadrant(angle))
|
890
|
+
writer.line(@x, @y, angle, length)
|
891
|
+
end
|
892
|
+
end
|
893
|
+
|
894
|
+
def origin_for_quadrant(quadrant)
|
895
|
+
x_offset = (content_width - preferred_content_width).quo(2)
|
896
|
+
y_offset = (content_height - preferred_content_height).quo(2)
|
897
|
+
# puts "x_offset: #{x_offset}, y_offset: #{y_offset}"
|
898
|
+
case quadrant
|
899
|
+
when 1 then [content_left + x_offset, content_bottom - y_offset]
|
900
|
+
when 2 then [content_right - x_offset, content_bottom - y_offset]
|
901
|
+
when 3 then [content_right - x_offset, content_top + y_offset]
|
902
|
+
else [content_left + x_offset, content_top + y_offset]
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
906
|
+
def preferred_content_width
|
907
|
+
Math::cos(angle.degrees) * length
|
908
|
+
end
|
909
|
+
|
910
|
+
def preferred_content_height
|
911
|
+
Math::sin(angle.degrees) * length
|
912
|
+
end
|
913
|
+
|
914
|
+
def quadrant(angle)
|
915
|
+
a = angle % 360
|
916
|
+
if a <= 90 then 1
|
917
|
+
elsif a <= 180 then 2
|
918
|
+
elsif a <= 270 then 3
|
919
|
+
else 4
|
920
|
+
end
|
921
|
+
end
|
922
|
+
end
|
923
|
+
|
924
|
+
class Pie < Arc
|
925
|
+
StdWidgetFactory.instance.register_widget('pie', self)
|
926
|
+
|
927
|
+
protected
|
928
|
+
def draw_content(writer)
|
929
|
+
# TODO
|
930
|
+
end
|
931
|
+
end
|
932
|
+
|
933
|
+
class Star < Widget
|
934
|
+
StdWidgetFactory.instance.register_widget('star', self)
|
935
|
+
|
936
|
+
include Shape
|
937
|
+
|
938
|
+
def reverse(value=nil)
|
939
|
+
# TODO
|
940
|
+
end
|
941
|
+
|
942
|
+
def rotation(value=nil)
|
943
|
+
# TODO
|
944
|
+
end
|
945
|
+
|
946
|
+
def points(value=nil)
|
947
|
+
# TODO
|
948
|
+
end
|
949
|
+
|
950
|
+
def r(value=nil)
|
951
|
+
# TODO
|
952
|
+
end
|
953
|
+
|
954
|
+
protected
|
955
|
+
def draw_content(writer)
|
956
|
+
# TODO
|
957
|
+
end
|
958
|
+
end
|
959
|
+
|
960
|
+
module Text
|
961
|
+
def layout_widget(writer)
|
962
|
+
super(writer)
|
963
|
+
font.apply(writer)
|
964
|
+
end
|
965
|
+
|
966
|
+
def has_height?
|
967
|
+
true
|
968
|
+
end
|
969
|
+
|
970
|
+
def has_width?
|
971
|
+
!@width_pct
|
972
|
+
end
|
973
|
+
|
974
|
+
def strikeout(value=nil)
|
975
|
+
return font.strikeout if value.nil?
|
976
|
+
font(:copy).strikeout(value)
|
977
|
+
end
|
978
|
+
|
979
|
+
def underline(value=nil)
|
980
|
+
return font.underline if value.nil?
|
981
|
+
font(:copy).underline(value)
|
982
|
+
end
|
983
|
+
|
984
|
+
def line_height(value=nil)
|
985
|
+
return font.line_height if value.nil?
|
986
|
+
font(:copy).line_height(value)
|
987
|
+
end
|
988
|
+
|
989
|
+
protected
|
990
|
+
def draw_content(writer)
|
991
|
+
font.apply(writer)
|
992
|
+
end
|
993
|
+
end
|
994
|
+
|
995
|
+
class Span < Widget
|
996
|
+
StdWidgetFactory.instance.register_widget('span', self)
|
997
|
+
|
998
|
+
include Text
|
999
|
+
|
1000
|
+
def initialize(parent, attrs={})
|
1001
|
+
raise ArgumentError, "Span must be child of Paragraph, Label or another Span." unless valid_parent?(parent)
|
1002
|
+
super(parent, attrs)
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
def printed
|
1006
|
+
true
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def text(value=nil, font=nil)
|
1010
|
+
return super if value.nil?
|
1011
|
+
parent.text(value, font || self.font)
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
private
|
1015
|
+
def valid_parent?(parent)
|
1016
|
+
parent.is_a?(Span) or parent.is_a?(Paragraph) or parent.is_a?(Label)
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
class PageNo < Span
|
1021
|
+
StdWidgetFactory.instance.register_widget('pageno', self)
|
1022
|
+
|
1023
|
+
def initialize(parent, attrs={})
|
1024
|
+
super(parent, attrs)
|
1025
|
+
parent.text(self)
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
def before_layout
|
1029
|
+
super
|
1030
|
+
root.document_page_no = @new_page_no if @new_page_no
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
def text(value=nil)
|
1034
|
+
return root.document_page_no.to_s if value.nil?
|
1035
|
+
@new_page_no = value.to_i
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
def to_s
|
1039
|
+
text
|
1040
|
+
end
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
class PreformattedText < Widget
|
1044
|
+
StdWidgetFactory.instance.register_widget('pre', self)
|
1045
|
+
|
1046
|
+
include Text
|
1047
|
+
|
1048
|
+
def initialize(parent, attrs={})
|
1049
|
+
@lines = []
|
1050
|
+
super(parent, attrs)
|
1051
|
+
font('fixed') if @font.nil?
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
def text(value=nil)
|
1055
|
+
return @lines if value.nil?
|
1056
|
+
value.lstrip! if @lines.empty?
|
1057
|
+
@lines.concat(value.split("\n")) unless value.empty?
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
def layout_widget(writer)
|
1061
|
+
super(writer)
|
1062
|
+
@lines.pop while @lines.last.strip.empty?
|
1063
|
+
@height ||= preferred_height(writer)
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def preferred_width(writer, units=:pt)
|
1067
|
+
font.apply(writer)
|
1068
|
+
@preferred_width = @width || @lines.map { |line| writer.width(line) }.max + non_content_width
|
1069
|
+
to_units(units, @preferred_width)
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
def preferred_height(writer, units=:pt)
|
1073
|
+
font.apply(writer)
|
1074
|
+
@preferred_height = writer.height(@lines) + non_content_height - (writer.height - writer.height.quo(writer.line_height))
|
1075
|
+
to_units(units, @preferred_height)
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
def url(value=nil)
|
1079
|
+
return @url if value.nil?
|
1080
|
+
@url = value
|
1081
|
+
text(text_for(@url))
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
protected
|
1085
|
+
def draw_content(writer)
|
1086
|
+
raise Exception, "left & top must be set: #{text.inspect}" if left.nil? or top.nil?
|
1087
|
+
font.apply(writer)
|
1088
|
+
writer.puts_xy(content_left, content_top + writer.text_ascent, @lines)
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
def text_for(url)
|
1092
|
+
open(url) { |f| f.read }
|
1093
|
+
rescue Exception => e
|
1094
|
+
raise RuntimeError, "Error opening #{url}", e.backtrace
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
class Container < Widget
|
1099
|
+
StdWidgetFactory.instance.register_widget('div', self)
|
1100
|
+
|
1101
|
+
attr_reader :children
|
1102
|
+
|
1103
|
+
def initialize(parent, attrs={})
|
1104
|
+
super(parent, attrs)
|
1105
|
+
@children = []
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def initialize_copy(other)
|
1109
|
+
super(other)
|
1110
|
+
@children = other.children.map { |child| child.clone }
|
1111
|
+
@children.each { |child| child.parent = self }
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
def after_layout
|
1115
|
+
# puts "after_layout: #{tag}"
|
1116
|
+
layout.manager.after_layout(self) unless layout.nil?
|
1117
|
+
children.each do |widget|
|
1118
|
+
widget.after_layout if widget.visible
|
1119
|
+
end
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
def cols(value=nil)
|
1123
|
+
return @cols if value.nil?
|
1124
|
+
@cols = value.to_i if value.to_i > 0
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
def layout(value=nil)
|
1128
|
+
return @layout_style || layout('vbox') if value.nil?
|
1129
|
+
@layout_style = layout_style_for(value)
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
def layout_container(writer)
|
1133
|
+
layout.manager.layout(self, writer)
|
1134
|
+
# returns count
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
def layout_widget(writer)
|
1138
|
+
super(writer)
|
1139
|
+
layout_container(writer)
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
def leaf?
|
1143
|
+
children.empty?
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
def leaves
|
1147
|
+
visible ? children.select { |w| w.visible }.inject(0) { |m, widget| m + widget.leaves } + super : 0
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
def more(flag=nil)
|
1151
|
+
parent.more(flag)
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
def order(value=nil)
|
1155
|
+
return @order || :rows if value.nil?
|
1156
|
+
@order = value.to_sym if [:rows, :cols].include?(value.to_sym)
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
def overflow(value=nil)
|
1160
|
+
return @overflow if value.nil?
|
1161
|
+
@overflow = case value
|
1162
|
+
when true, 'true' then true
|
1163
|
+
when false, 'false' then false
|
1164
|
+
else value.to_s
|
1165
|
+
end
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
def paragraph_style(value=nil)
|
1169
|
+
return @paragraph_style || parent.paragraph_style if value.nil?
|
1170
|
+
@paragraph_style = paragraph_style_for(value)
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
def preferred_content_height(writer)
|
1174
|
+
@preferred_content_height ||= layout.manager.preferred_height(layout_grid, writer)
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
def preferred_content_width(writer)
|
1178
|
+
@preferred_content_width ||= layout.manager.preferred_width(layout_grid, writer)
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
def preferred_height(writer, units=:pt)
|
1182
|
+
@preferred_height ||= @height || (preferred_content_height(writer) || return) + non_content_height
|
1183
|
+
to_units(units, overflow ? [@preferred_height, max_height_avail].min : @preferred_height)
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
def preferred_width(writer, units=:pt)
|
1187
|
+
@preferred_width ||= @width || (preferred_content_width(writer) || return) + non_content_width
|
1188
|
+
to_units(units, @preferred_width)
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
def printed
|
1192
|
+
disabled or (super and children.all? { |widget| widget.printed })
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def rows(value=nil)
|
1196
|
+
return @rows if value.nil?
|
1197
|
+
@rows = value.to_i if value.to_i > 0
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
def source(id=nil)
|
1201
|
+
return children if id.nil?
|
1202
|
+
@children = widget_for(id).children
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
def visible(bounds=nil)
|
1206
|
+
bounds.nil? ? super : super + children.inject(0) { |total, widget| total + widget.visible(bounds) }
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
protected
|
1210
|
+
def draw_content(writer)
|
1211
|
+
super(writer)
|
1212
|
+
children.sort { |a, b| a.z_index <=> b.z_index }.each { |child| child.print(writer) }
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
def layout_grid
|
1216
|
+
@layout_grid ||= layout.manager.grid(self)
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
def layout_style_for(id)
|
1220
|
+
ls = root.styles.for_id(id)
|
1221
|
+
raise ArgumentError, "Layout Style #{id} not found." unless ls.is_a?(Styles::LayoutStyle)
|
1222
|
+
ls
|
1223
|
+
end
|
1224
|
+
|
1225
|
+
def paragraph_style_for(id)
|
1226
|
+
ps = root.styles.for_id(id)
|
1227
|
+
raise ArgumentError, "Paragraph Style #{id} not found." unless ps.is_a?(Styles::ParagraphStyle)
|
1228
|
+
ps
|
1229
|
+
end
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
class Circle < Container
|
1233
|
+
StdWidgetFactory.instance.register_widget('circle', self)
|
1234
|
+
|
1235
|
+
include Shape
|
1236
|
+
|
1237
|
+
def before_layout
|
1238
|
+
super
|
1239
|
+
@width ||= @height
|
1240
|
+
@height ||= @width
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
def clip(value=nil)
|
1244
|
+
# TODO
|
1245
|
+
end
|
1246
|
+
|
1247
|
+
def default_padding_top
|
1248
|
+
(@preferred_height and @preferred_content_height) ? @preferred_radius - @preferred_content_height / 2.0 : 0
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
def default_padding_right
|
1252
|
+
(@preferred_width and @preferred_content_width) ? @preferred_radius - @preferred_content_width / 2.0 : 0
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
def default_padding_bottom
|
1256
|
+
(@preferred_height and @preferred_content_height) ? @preferred_radius - @preferred_content_height / 2.0 : 0
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
def default_padding_left
|
1260
|
+
(@preferred_width and @preferred_content_width) ? @preferred_radius - @preferred_content_width / 2.0 : 0
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
def preferred_radius(writer, units=:pt)
|
1264
|
+
@preferred_radius ||= begin
|
1265
|
+
pcw, pch = preferred_content_width(writer), preferred_content_height(writer)
|
1266
|
+
return if pcw.nil? and pch.nil?
|
1267
|
+
Math.sqrt(((pcw || pch) / 2.0) ** 2 + ((pch || pcw) / 2.0) ** 2)
|
1268
|
+
end
|
1269
|
+
to_units(units, @preferred_radius)
|
1270
|
+
end
|
1271
|
+
|
1272
|
+
def preferred_height(writer, units=:pt)
|
1273
|
+
@preferred_height ||= @height || @width || ((preferred_radius(writer) || return) * 2 + non_content_height)
|
1274
|
+
to_units(units, @preferred_height)
|
1275
|
+
end
|
1276
|
+
|
1277
|
+
def preferred_width(writer, units=:pt)
|
1278
|
+
@preferred_width ||= @width || @height || ((preferred_radius(writer) || return) * 2 + non_content_width)
|
1279
|
+
to_units(units, @preferred_width)
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
def r(value=nil, units=nil)
|
1283
|
+
return @r if value.nil?
|
1284
|
+
return to_units(value, @r) if value.is_a?(Symbol)
|
1285
|
+
@r = parse_measurement_pts(value, units || self.units)
|
1286
|
+
@r = [(width - margin_left - margin_right).quo(2), (height - margin_top - margin_bottom).quo(2)].min + @r if @r < 0
|
1287
|
+
@width ||= @r * 2 + margin_left + margin_right
|
1288
|
+
@height ||= @r * 2 + margin_top + margin_bottom
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
def reverse(value=nil)
|
1292
|
+
# TODO
|
1293
|
+
end
|
1294
|
+
|
1295
|
+
protected
|
1296
|
+
def before_print(writer)
|
1297
|
+
# puts "left: #{left}, margin_left: #{margin_left}, right: #{right}, margin_right: #{margin_right}"
|
1298
|
+
@x ||= (left + margin_left + right - margin_right).quo(2)
|
1299
|
+
@y ||= (top + margin_top + bottom - margin_bottom).quo(2)
|
1300
|
+
# puts "before_print 1 @r: #{@r.inspect}"
|
1301
|
+
# puts "@r ||= [(#{width} - #{margin_left} - #{margin_right}).quo(2), (#{height} - #{margin_top} - #{margin_bottom}).quo(2)].min"
|
1302
|
+
@r ||= [(width - margin_left - margin_right).quo(2), (height - margin_top - margin_bottom).quo(2)].min
|
1303
|
+
# @r ||= preferred_radius(writer)
|
1304
|
+
# @width ||= @r * 2 + margin_left + margin_right
|
1305
|
+
# @height ||= @r * 2 + margin_top + margin_bottom
|
1306
|
+
# puts "before_print 2 @r: #{@r.inspect}"
|
1307
|
+
super(writer)
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
def height_set
|
1311
|
+
@preferred_height ||= @height
|
1312
|
+
@preferred_width ||= @height
|
1313
|
+
end
|
1314
|
+
|
1315
|
+
def width_set
|
1316
|
+
@preferred_width ||= @width
|
1317
|
+
@preferred_height ||= @width
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
def x_offset
|
1321
|
+
(position == :relative) ? parent.content_left : 0
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
def y_offset
|
1325
|
+
(position == :relative) ? parent.content_top : 0
|
1326
|
+
end
|
1327
|
+
|
1328
|
+
def draw_content(writer)
|
1329
|
+
super(writer)
|
1330
|
+
options = {}
|
1331
|
+
options[:border] = !!@border
|
1332
|
+
options[:fill] = !!@fill
|
1333
|
+
@border.apply(writer) unless @border.nil?
|
1334
|
+
@fill.apply(writer) unless @fill.nil?
|
1335
|
+
# puts "writer.circle(#{@x} + #{x_offset}, #{@y} + #{y_offset}, #{r}, #{options.inspect})"
|
1336
|
+
writer.circle(@x + x_offset, @y + y_offset, r, options)
|
1337
|
+
end
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
class Ellipse < Container
|
1341
|
+
StdWidgetFactory.instance.register_widget('ellipse', self)
|
1342
|
+
|
1343
|
+
include Shape
|
1344
|
+
|
1345
|
+
def rotation(value=nil)
|
1346
|
+
# TODO
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
def rx(value=nil)
|
1350
|
+
return @rx if value.nil?
|
1351
|
+
return to_units(value, @rx) if value.is_a?(Symbol)
|
1352
|
+
@rx = parse_measurement_pts(value, units || self.units)
|
1353
|
+
@rx = (width - margin_left - margin_right).quo(2) + @rx if @rx < 0
|
1354
|
+
@width ||= @rx * 2 + margin_left + margin_right
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
def ry(value=nil)
|
1358
|
+
return @ry if value.nil?
|
1359
|
+
return to_units(value, @ry) if value.is_a?(Symbol)
|
1360
|
+
@ry = parse_measurement_pts(value, units || self.units)
|
1361
|
+
@ry = (height - margin_top - margin_bottom).quo(2) + @ry if @ry < 0
|
1362
|
+
@height ||= @ry * 2 + margin_top + margin_bottom
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
protected
|
1366
|
+
def draw_content(writer)
|
1367
|
+
@x ||= (content_left + content_right).quo(2)
|
1368
|
+
@y ||= (content_top + content_bottom).quo(2)
|
1369
|
+
@rx ||= (width - margin_left - margin_right).quo(2)
|
1370
|
+
@ry ||= (height - margin_top - margin_bottom).quo(2)
|
1371
|
+
options = {}
|
1372
|
+
options[:border] = !!@border
|
1373
|
+
options[:fill] = !!@fill
|
1374
|
+
@border.apply(writer) unless @border.nil?
|
1375
|
+
@fill.apply(writer) unless @fill.nil?
|
1376
|
+
x_offset, y_offset = (position == :relative) ? [parent.content_left, parent.content_top] : [0, 0]
|
1377
|
+
writer.ellipse(@x + x_offset, @y + y_offset, @rx, @ry, options)
|
1378
|
+
super(writer)
|
1379
|
+
end
|
1380
|
+
end
|
1381
|
+
|
1382
|
+
class Label < Container
|
1383
|
+
StdWidgetFactory.instance.register_widget('label', self)
|
1384
|
+
|
1385
|
+
include HasLocation
|
1386
|
+
include Text
|
1387
|
+
|
1388
|
+
def angle(value=nil)
|
1389
|
+
return style.angle if value.nil?
|
1390
|
+
style(:copy).angle(value)
|
1391
|
+
end
|
1392
|
+
|
1393
|
+
def before_layout
|
1394
|
+
children.each { |child| child.before_layout }
|
1395
|
+
end
|
1396
|
+
|
1397
|
+
def layout_container(writer)
|
1398
|
+
# suppress default behavior
|
1399
|
+
0
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
def preferred_width(writer, units=:pt)
|
1403
|
+
font.apply(writer)
|
1404
|
+
to_units(units, writer.width(text) + non_content_width)
|
1405
|
+
end
|
1406
|
+
|
1407
|
+
def preferred_height(writer, units=:pt)
|
1408
|
+
font.apply(writer)
|
1409
|
+
to_units(units, writer.text_height + non_content_height)
|
1410
|
+
end
|
1411
|
+
|
1412
|
+
def style(value=nil)
|
1413
|
+
return @style ||= label_style_for('label') if value.nil?
|
1414
|
+
return @style = style.clone if value == :copy
|
1415
|
+
@style = label_style_for(value)
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
def text(value=nil)
|
1419
|
+
@text_pieces ||= []
|
1420
|
+
return @text_pieces.join if value.nil?
|
1421
|
+
value.lstrip! if @text_pieces.empty? and value.respond_to?(:lstrip!)
|
1422
|
+
@text_pieces << value unless value.respond_to?(:empty?) and value.empty?
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
def text_align(value=nil)
|
1426
|
+
return style.text_align if value.nil?
|
1427
|
+
style(:copy).text_align(value)
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
protected
|
1431
|
+
def before_print(writer)
|
1432
|
+
@width ||= preferred_width(writer)
|
1433
|
+
@height ||= preferred_height(writer)
|
1434
|
+
super(writer)
|
1435
|
+
end
|
1436
|
+
|
1437
|
+
def draw_content(writer)
|
1438
|
+
super(writer)
|
1439
|
+
options = { :angle => angle, :underline => underline }
|
1440
|
+
@y ||= content_top
|
1441
|
+
case text_align
|
1442
|
+
when :left
|
1443
|
+
@x ||= content_left
|
1444
|
+
when :center
|
1445
|
+
@x ||= (content_left + content_right).quo(2)
|
1446
|
+
options[:align] = :center
|
1447
|
+
when :right
|
1448
|
+
@x ||= content_right
|
1449
|
+
options[:align] = :right
|
1450
|
+
end
|
1451
|
+
writer.print_xy(@x, @y + writer.text_ascent, text, options)
|
1452
|
+
end
|
1453
|
+
|
1454
|
+
def label_style_for(id)
|
1455
|
+
ls = root.styles.for_id(id)
|
1456
|
+
raise ArgumentError, "Label Style #{id} not found." unless ls.is_a?(Styles::LabelStyle)
|
1457
|
+
ls
|
1458
|
+
end
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
class Paragraph < Container
|
1462
|
+
StdWidgetFactory.instance.register_widget('p', self)
|
1463
|
+
|
1464
|
+
include Text
|
1465
|
+
|
1466
|
+
def before_layout
|
1467
|
+
children.each { |child| child.before_layout }
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
def bullet(value=nil)
|
1471
|
+
return @bullet.nil? ? style.bullet : @bullet if value.nil?
|
1472
|
+
@bullet = bullet_style_for(value)
|
1473
|
+
end
|
1474
|
+
|
1475
|
+
def layout_container(writer)
|
1476
|
+
# suppress default behavior
|
1477
|
+
0
|
1478
|
+
end
|
1479
|
+
|
1480
|
+
def layout_widget(writer)
|
1481
|
+
super(writer)
|
1482
|
+
@height ||= preferred_height(writer)
|
1483
|
+
end
|
1484
|
+
|
1485
|
+
def preferred_width(writer, units=:pt)
|
1486
|
+
@preferred_width = @width || begin
|
1487
|
+
(rich_text(writer).width(root_page.width - bullet_width - non_content_width) || 0) + bullet_width + non_content_width + 1
|
1488
|
+
end
|
1489
|
+
to_units(units, @preferred_width)
|
1490
|
+
end
|
1491
|
+
|
1492
|
+
def preferred_height(writer, units=:pt)
|
1493
|
+
@preferred_height = @height || begin
|
1494
|
+
ph = if width.nil?
|
1495
|
+
rich_text(writer).height(parent.content_width - bullet_width - non_content_width) * line_height
|
1496
|
+
else
|
1497
|
+
rich_text(writer).height(content_width - bullet_width) * line_height
|
1498
|
+
end
|
1499
|
+
@preferred_height = ph + non_content_height - rich_text(writer).height * (line_height - 1)
|
1500
|
+
end
|
1501
|
+
to_units(units, @preferred_height)
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
def style(value=nil)
|
1505
|
+
# inherited
|
1506
|
+
return @style || parent.paragraph_style if value.nil?
|
1507
|
+
return @style || @style = parent.paragraph_style.clone if value == :copy
|
1508
|
+
@style = paragraph_style_for(value)
|
1509
|
+
end
|
1510
|
+
|
1511
|
+
def text(value=nil, font=nil)
|
1512
|
+
return @text_pieces if value.nil?
|
1513
|
+
value.gsub!(/\n\s*/, ' ') if value.respond_to?(:gsub!)
|
1514
|
+
@text_pieces ||= []
|
1515
|
+
value.lstrip! if @text_pieces.empty? and value.respond_to?(:lstrip!)
|
1516
|
+
@text_pieces << [value, font || self.font] unless value.respond_to?(:empty?) and value.empty?
|
1517
|
+
end
|
1518
|
+
|
1519
|
+
def text_align(value=nil)
|
1520
|
+
return style.text_align if value.nil?
|
1521
|
+
@style = style.clone
|
1522
|
+
@style.text_align(value)
|
1523
|
+
end
|
1524
|
+
|
1525
|
+
protected
|
1526
|
+
def bullet_style_for(id)
|
1527
|
+
bs = root.styles.for_id(id)
|
1528
|
+
raise ArgumentError, "Bullet Style #{value} not found." unless bs.is_a?(Styles::BulletStyle)
|
1529
|
+
bs
|
1530
|
+
end
|
1531
|
+
|
1532
|
+
def bullet_width
|
1533
|
+
bullet.nil? ? 0 : bullet.width
|
1534
|
+
end
|
1535
|
+
|
1536
|
+
def draw_content(writer)
|
1537
|
+
super(writer)
|
1538
|
+
options = { :align => style.text_align, :underline => underline, :width => content_width }
|
1539
|
+
unless bullet.nil?
|
1540
|
+
bullet.apply(writer)
|
1541
|
+
options[:bullet] = bullet.id unless bullet.nil?
|
1542
|
+
end
|
1543
|
+
pen_style_for('solid').apply(writer)
|
1544
|
+
raise Exception, "left & top must be set: #{text.inspect}" if left.nil? or top.nil?
|
1545
|
+
writer.paragraph_xy(content_left, content_top + rich_text(writer).ascent(content_width), rich_text(writer), options)
|
1546
|
+
@rich_text = nil
|
1547
|
+
end
|
1548
|
+
|
1549
|
+
def paragraph_style_for(id)
|
1550
|
+
ps = root.styles.for_id(id)
|
1551
|
+
raise ArgumentError, "Paragraph Style #{id} not found." unless ps.is_a?(Styles::ParagraphStyle)
|
1552
|
+
ps
|
1553
|
+
end
|
1554
|
+
|
1555
|
+
def rich_text(writer)
|
1556
|
+
if @rich_text.nil?
|
1557
|
+
@text_pieces ||= []
|
1558
|
+
# Trim trailing whitespace.
|
1559
|
+
while !@text_pieces.empty? and @text_pieces.last[0].respond_to?(:to_str) and @text_pieces.last[0].rstrip!
|
1560
|
+
@text_pieces.pop if @text_pieces.last[0].empty?
|
1561
|
+
end
|
1562
|
+
@rich_text = EideticPDF::PdfText::RichText.new
|
1563
|
+
@text_pieces.each do |piece|
|
1564
|
+
text, font = piece
|
1565
|
+
font.apply(writer)
|
1566
|
+
@rich_text.add(text.to_s, writer.font, :color => font.color, :underline => font.underline)
|
1567
|
+
end unless @text_pieces.nil?
|
1568
|
+
end
|
1569
|
+
@rich_text
|
1570
|
+
end
|
1571
|
+
end
|
1572
|
+
|
1573
|
+
class Polygon < Container
|
1574
|
+
StdWidgetFactory.instance.register_widget('polygon', self)
|
1575
|
+
|
1576
|
+
include Shape
|
1577
|
+
|
1578
|
+
def clip(value=nil)
|
1579
|
+
# TODO
|
1580
|
+
end
|
1581
|
+
|
1582
|
+
def r(value=nil)
|
1583
|
+
return @r if value.nil?
|
1584
|
+
return to_units(value, @r) if value.is_a?(Symbol)
|
1585
|
+
@r = parse_measurement_pts(value, units || self.units)
|
1586
|
+
@r = [(width - margin_left - margin_right).quo(2), (height - margin_top - margin_bottom).quo(2)].min + @r if @r < 0
|
1587
|
+
@width ||= @r * 2 + margin_left + margin_right
|
1588
|
+
@height ||= @r * 2 + margin_top + margin_bottom
|
1589
|
+
end
|
1590
|
+
|
1591
|
+
def reverse(value=nil)
|
1592
|
+
# TODO
|
1593
|
+
end
|
1594
|
+
|
1595
|
+
def rotation(value=nil)
|
1596
|
+
return @rotation if value.nil?
|
1597
|
+
@rotation = value.to_f
|
1598
|
+
end
|
1599
|
+
|
1600
|
+
def sides(value=nil)
|
1601
|
+
return @sides || 3 if value.nil?
|
1602
|
+
@sides = value.to_i if value.to_i >= 3
|
1603
|
+
end
|
1604
|
+
|
1605
|
+
protected
|
1606
|
+
def draw_content(writer)
|
1607
|
+
@x ||= (content_left + content_right).quo(2)
|
1608
|
+
@y ||= (content_top + content_bottom).quo(2)
|
1609
|
+
@r ||= [(width - margin_left - margin_right).quo(2), (height - margin_top - margin_bottom).quo(2)].min
|
1610
|
+
options = {}
|
1611
|
+
options[:border] = !!@border
|
1612
|
+
options[:fill] = !!@fill
|
1613
|
+
options[:rotation] = @rotation
|
1614
|
+
@border.apply(writer) unless @border.nil?
|
1615
|
+
@fill.apply(writer) unless @fill.nil?
|
1616
|
+
x_offset, y_offset = (position == :relative) ? [parent.content_left, parent.content_top] : [0, 0]
|
1617
|
+
writer.polygon(@x + x_offset, @y + y_offset, @r, sides, options)
|
1618
|
+
super(writer)
|
1619
|
+
end
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
class Rectangle < Container
|
1623
|
+
StdWidgetFactory.instance.register_widget('rect', self)
|
1624
|
+
|
1625
|
+
include Shape
|
1626
|
+
|
1627
|
+
def clip(value=nil)
|
1628
|
+
# TODO
|
1629
|
+
end
|
1630
|
+
|
1631
|
+
def corners(value=nil)
|
1632
|
+
return @corners if value.nil?
|
1633
|
+
value = value.split(',') if value.respond_to?(:to_str)
|
1634
|
+
value = Array(value)
|
1635
|
+
@corners = value.map { |n| parse_measurement_pts(n, units) } if [1,2,4,8].include?(value.size)
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
# def path(value=nil)
|
1639
|
+
# # TODO
|
1640
|
+
# end
|
1641
|
+
|
1642
|
+
def reverse(value=nil)
|
1643
|
+
# TODO
|
1644
|
+
end
|
1645
|
+
|
1646
|
+
protected
|
1647
|
+
def draw_content(writer)
|
1648
|
+
raise Exception, "left, top, width & height must be set" if [left, top, width, height].any? { |value| value.nil? }
|
1649
|
+
options = {}
|
1650
|
+
options[:corners] = @corners unless @corners.nil?
|
1651
|
+
options[:border] = !!@border
|
1652
|
+
options[:fill] = !!@fill
|
1653
|
+
@border.apply(writer) unless @border.nil?
|
1654
|
+
@fill.apply(writer) unless @fill.nil?
|
1655
|
+
writer.rectangle(left + margin_left, top + margin_top,
|
1656
|
+
width - margin_left - margin_right, height - margin_top - margin_bottom,
|
1657
|
+
options)
|
1658
|
+
super(writer)
|
1659
|
+
end
|
1660
|
+
end
|
1661
|
+
|
1662
|
+
class Page < Container
|
1663
|
+
StdWidgetFactory.instance.register_widget('page', self)
|
1664
|
+
|
1665
|
+
def initialize(parent, attrs={})
|
1666
|
+
@default_margin = true
|
1667
|
+
@more = true
|
1668
|
+
@overflow = true
|
1669
|
+
super(parent, attrs)
|
1670
|
+
raise ArgumentError, "Page must be child of Document." unless parent.nil? or parent.is_a?(Document)
|
1671
|
+
end
|
1672
|
+
|
1673
|
+
def bottom(units=:pt)
|
1674
|
+
height(units)
|
1675
|
+
end
|
1676
|
+
|
1677
|
+
def compress(value=nil)
|
1678
|
+
# TODO
|
1679
|
+
end
|
1680
|
+
|
1681
|
+
def crop(value=nil)
|
1682
|
+
# inherited
|
1683
|
+
# TODO
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
def height(units=:pt)
|
1687
|
+
to_units(units, style.height)
|
1688
|
+
end
|
1689
|
+
|
1690
|
+
def left(units=:pt)
|
1691
|
+
0
|
1692
|
+
end
|
1693
|
+
|
1694
|
+
def margin(value=nil)
|
1695
|
+
# inherited
|
1696
|
+
return @default_margin ? parent.margin(value) : super(value) if value.nil? or value.is_a?(Symbol)
|
1697
|
+
super(value)
|
1698
|
+
@default_margin = false
|
1699
|
+
end
|
1700
|
+
|
1701
|
+
def margin_top(value=nil)
|
1702
|
+
# inherited
|
1703
|
+
return @default_margin ? parent.margin_top(value) : super(value) if value.nil? or value.is_a?(Symbol)
|
1704
|
+
super(value)
|
1705
|
+
@default_margin = false
|
1706
|
+
end
|
1707
|
+
|
1708
|
+
def margin_right(value=nil)
|
1709
|
+
# inherited
|
1710
|
+
return @default_margin ? parent.margin_right(value) : super(value) if value.nil? or value.is_a?(Symbol)
|
1711
|
+
margin(margin) if @default_margin
|
1712
|
+
super(value)
|
1713
|
+
@default_margin = false
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
def margin_bottom(value=nil)
|
1717
|
+
# inherited
|
1718
|
+
return @default_margin ? parent.margin_bottom(value) : super(value) if value.nil? or value.is_a?(Symbol)
|
1719
|
+
margin(margin) if @default_margin
|
1720
|
+
super(value)
|
1721
|
+
@default_margin = false
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
def margin_left(value=nil)
|
1725
|
+
# inherited
|
1726
|
+
return @default_margin ? parent.margin_left(value) : super(value) if value.nil? or value.is_a?(Symbol)
|
1727
|
+
margin(margin) if @default_margin
|
1728
|
+
super(value)
|
1729
|
+
@default_margin = false
|
1730
|
+
end
|
1731
|
+
|
1732
|
+
def more(flag=nil)
|
1733
|
+
return @more if flag.nil?
|
1734
|
+
@more = flag
|
1735
|
+
end
|
1736
|
+
|
1737
|
+
def orientation(value=nil)
|
1738
|
+
# inherited
|
1739
|
+
return style.orientation if value.nil?
|
1740
|
+
style(:copy).orientation(value)
|
1741
|
+
end
|
1742
|
+
|
1743
|
+
def positioned_widgets
|
1744
|
+
@positioned_widgets ||= Hash.new(0)
|
1745
|
+
end
|
1746
|
+
|
1747
|
+
def print(writer)
|
1748
|
+
root.section_page_no = 0
|
1749
|
+
while more
|
1750
|
+
more(false)
|
1751
|
+
writer.open_page(:page_size => size, :orientation => orientation)
|
1752
|
+
root.document_page_no += 1
|
1753
|
+
root.section_page_no += 1
|
1754
|
+
positioned_widgets.clear
|
1755
|
+
# $stderr.puts "----before layout widget"
|
1756
|
+
layout_widget(writer)
|
1757
|
+
# after_layout
|
1758
|
+
# $stderr.puts "----before super print"
|
1759
|
+
super(writer)
|
1760
|
+
# $stderr.puts "----after super print"
|
1761
|
+
writer.close_page
|
1762
|
+
break if positioned_widgets[:static] == 0
|
1763
|
+
end
|
1764
|
+
end
|
1765
|
+
|
1766
|
+
def right(units=:pt)
|
1767
|
+
width(units)
|
1768
|
+
end
|
1769
|
+
|
1770
|
+
def root_page
|
1771
|
+
self
|
1772
|
+
end
|
1773
|
+
|
1774
|
+
def rotate(value=nil)
|
1775
|
+
# inherited
|
1776
|
+
# TODO
|
1777
|
+
end
|
1778
|
+
|
1779
|
+
def size(value=nil)
|
1780
|
+
# inherited
|
1781
|
+
return style.size if value.nil?
|
1782
|
+
style(:copy).size(value)
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
def style(value=nil)
|
1786
|
+
# inherited
|
1787
|
+
return @page_style || parent.page_style if value.nil?
|
1788
|
+
return @page_style || @page_style = parent.page_style.clone if value == :copy
|
1789
|
+
@page_style = page_style_for(value)
|
1790
|
+
end
|
1791
|
+
|
1792
|
+
def top(units=:pt)
|
1793
|
+
0
|
1794
|
+
end
|
1795
|
+
|
1796
|
+
def width(units=:pt)
|
1797
|
+
to_units(units, style.width)
|
1798
|
+
end
|
1799
|
+
|
1800
|
+
protected
|
1801
|
+
def page_style_for(id)
|
1802
|
+
ps = root.styles.for_id(id)
|
1803
|
+
raise ArgumentError, "Page Style #{id} not found." unless ps.is_a?(Styles::PageStyle)
|
1804
|
+
ps
|
1805
|
+
end
|
1806
|
+
end
|
1807
|
+
|
1808
|
+
class Document < Page
|
1809
|
+
StdWidgetFactory.instance.register_widget('erml', self)
|
1810
|
+
|
1811
|
+
alias :pages :children
|
1812
|
+
attr_accessor :document_page_no, :section_page_no
|
1813
|
+
|
1814
|
+
def initialize(parent=nil, attrs={})
|
1815
|
+
super(parent, attrs)
|
1816
|
+
@default_margin = false
|
1817
|
+
init_default_styles
|
1818
|
+
end
|
1819
|
+
|
1820
|
+
# def orientation(value=nil)
|
1821
|
+
# return @orientation || :portrait if value.nil?
|
1822
|
+
# super(value)
|
1823
|
+
# end
|
1824
|
+
|
1825
|
+
def rules
|
1826
|
+
@rules ||= Rules::RuleCollection.new
|
1827
|
+
end
|
1828
|
+
|
1829
|
+
def page_style(value=nil)
|
1830
|
+
return @page_style if value.nil?
|
1831
|
+
super(value)
|
1832
|
+
end
|
1833
|
+
|
1834
|
+
def pages_up(value=nil)
|
1835
|
+
return @pages_up || [1, 1] if value.nil?
|
1836
|
+
if value.respond_to?(:to_str)
|
1837
|
+
x, y = value.to_s.split(',', 2)
|
1838
|
+
else
|
1839
|
+
x, y = Array(value)
|
1840
|
+
end
|
1841
|
+
@pages_up = [x.to_i, y.to_i]
|
1842
|
+
end
|
1843
|
+
|
1844
|
+
def pages_up_layout(value=nil)
|
1845
|
+
return @pages_up_layout || :across if value.nil?
|
1846
|
+
@pages_up_layout = value.to_sym if [:across, :down].include?(value.to_sym)
|
1847
|
+
end
|
1848
|
+
|
1849
|
+
def print(writer)
|
1850
|
+
@document_page_no = 0
|
1851
|
+
writer.open(:v_text_align => :base, :pages_up => pages_up, :pages_up_layout => pages_up_layout, :orientation => orientation, :text_encoding => 'UTF-8')
|
1852
|
+
pages.each do |page|
|
1853
|
+
page.print(writer)
|
1854
|
+
end
|
1855
|
+
writer.close
|
1856
|
+
end
|
1857
|
+
|
1858
|
+
def styles
|
1859
|
+
@styles ||= Styles::StyleCollection.new
|
1860
|
+
end
|
1861
|
+
|
1862
|
+
def to_s
|
1863
|
+
writer = EideticPDF::DocumentWriter.new
|
1864
|
+
print(writer)
|
1865
|
+
writer.to_s
|
1866
|
+
end
|
1867
|
+
|
1868
|
+
def units(value=nil)
|
1869
|
+
return @units || :pt if value.nil?
|
1870
|
+
super(value)
|
1871
|
+
end
|
1872
|
+
|
1873
|
+
def widgets
|
1874
|
+
@widgets ||= {}
|
1875
|
+
end
|
1876
|
+
|
1877
|
+
private
|
1878
|
+
def init_default_styles
|
1879
|
+
@page_style = styles.add('page', :id => 'page')
|
1880
|
+
@font = styles.add('font', :id => 'font')
|
1881
|
+
@label_style = styles.add('label', :id => 'label')
|
1882
|
+
@paragraph_style = styles.add('para', :id => 'p')
|
1883
|
+
styles.add('layout', :id => 'absolute', :manager => 'absolute')
|
1884
|
+
styles.add('layout', :id => 'flow', :manager => 'flow', :padding => 5)
|
1885
|
+
styles.add('layout', :id => 'hbox', :manager => 'hbox')
|
1886
|
+
styles.add('layout', :id => 'vbox', :manager => 'vbox')
|
1887
|
+
styles.add('layout', :id => 'table', :manager => 'table', :padding => 5)
|
1888
|
+
styles.add('pen', :id => 'solid', :pattern => 'solid', :color => 'Black')
|
1889
|
+
styles.add('pen', :id => 'dotted', :pattern => 'dotted', :color => 'Black')
|
1890
|
+
styles.add('pen', :id => 'dashed', :pattern => 'dashed', :color => 'Black')
|
1891
|
+
styles.add('font', :id => 'fixed', :name => 'Courier', :size => 10)
|
1892
|
+
end
|
1893
|
+
end
|
1894
|
+
end
|
1895
|
+
end
|