ifmapper 1.0.8 → 1.0.9
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.
- data/HISTORY.txt +4 -0
- data/IFMapper.gemspec +1 -1
- data/TODO.txt +0 -2
- data/docs/en/index.html +1 -1
- data/lib/IFMapper/FXMap.rb +35 -23
- data/lib/IFMapper/FXMapperWindow.rb +2 -1
- data/lib/IFMapper/PDFMapExporter_pdfwriter.rb +526 -0
- data/lib/IFMapper/PDFMapExporter_prawn.rb +528 -0
- data/lib/IFMapper/Room.rb +1 -0
- data/lib/IFMapper/TranscriptReader.rb +61 -0
- data/lib/IFMapper/locales/en/Messages.rb +13 -1
- data/lib/IFMapper/locales/es/Messages.rb +13 -2
- data/maps/Bronze.map +0 -0
- data/maps/Bureaucracy.map +0 -0
- data/maps/Byzantine.map +0 -0
- data/maps/CityOfSecrets.map +0 -0
- data/maps/Condemned.map +0 -0
- data/maps/Duel_in_the_Snow.map +0 -0
- data/maps/Eruption.map +0 -0
- data/maps/Gatoron.map +0 -0
- data/maps/Spelunker's_Quest.map +0 -0
- metadata +66 -61
- data/docs/en/start.html~ +0 -516
data/HISTORY.txt
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
v1.0.9 - Bug fixed crash of cut selection when stubs were present.
|
2
|
+
- Added option to automap rooms with all caps.
|
3
|
+
- Bug fixed Select All rooms to show the selection.
|
4
|
+
|
1
5
|
v1.0.8 - Added option to load a map from command-line.
|
2
6
|
- Bug fixed pdf output of letters near exits.
|
3
7
|
- Added support for comments in each location.
|
data/IFMapper.gemspec
CHANGED
@@ -2,7 +2,7 @@ require "rubygems"
|
|
2
2
|
|
3
3
|
spec = Gem::Specification.new do |spec|
|
4
4
|
spec.name = "ifmapper"
|
5
|
-
spec.version = '1.0.
|
5
|
+
spec.version = '1.0.9'
|
6
6
|
spec.author = "Gonzalo Garramuno"
|
7
7
|
spec.email = 'ggarra13@gmail.com'
|
8
8
|
spec.homepage = 'http://www.rubyforge.org/projects/ifmapper/'
|
data/TODO.txt
CHANGED
data/docs/en/index.html
CHANGED
@@ -16,7 +16,7 @@ Interactive</span> Fiction Mapper</a></font></b></u></p>
|
|
16
16
|
<p align="center"><a href="images/IFMapper_main.gif">
|
17
17
|
<img border="0" src="../images/IFMapper_main.gif" width="595" height="447"></a></p>
|
18
18
|
<p align="center">
|
19
|
-
<a href="
|
19
|
+
<a href="start.html">A Tool for
|
20
20
|
Mapping Interactive Fiction</a></p>
|
21
21
|
|
22
22
|
</body>
|
data/lib/IFMapper/FXMap.rb
CHANGED
@@ -27,8 +27,8 @@ class FXMap < Map
|
|
27
27
|
# automapping
|
28
28
|
attr_reader :automap # automapping transcript
|
29
29
|
|
30
|
-
attr_reader :complexConnection
|
31
|
-
attr_reader :mouseButton
|
30
|
+
attr_reader :complexConnection # Complex connection in progress
|
31
|
+
attr_reader :mouseButton # Mouse button pressed
|
32
32
|
|
33
33
|
|
34
34
|
# pmap is a path map (a matrix or grid used for path finding).
|
@@ -41,6 +41,7 @@ class FXMap < Map
|
|
41
41
|
@@roomlist = nil # Room List Window
|
42
42
|
@@itemlist = nil # Item List Window
|
43
43
|
|
44
|
+
# Cursors
|
44
45
|
@@tooltip = nil
|
45
46
|
@@cursor_arrow = nil
|
46
47
|
@@cursor_cross = nil
|
@@ -875,7 +876,7 @@ class FXMap < Map
|
|
875
876
|
@tooltip_msg = sel.name
|
876
877
|
status "\"#{sel.name}\": #{MSG_CLICK_TO_SELECT_AND_MOVE}"
|
877
878
|
elsif sel.kind_of?(Connection)
|
878
|
-
status
|
879
|
+
status MSG_CLICK_TOGGLE_ONE_WAY_CONNECTION
|
879
880
|
end
|
880
881
|
else
|
881
882
|
if click_type(x, y)
|
@@ -1427,17 +1428,24 @@ class FXMap < Map
|
|
1427
1428
|
rooms, conns = _cut_selected
|
1428
1429
|
|
1429
1430
|
# Remove room exits pointing to any removed connection
|
1430
|
-
conns
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1431
|
+
if conns
|
1432
|
+
conns.each { |c|
|
1433
|
+
a = c.roomA
|
1434
|
+
b = c.roomB
|
1435
|
+
if not rooms.member?(a)
|
1436
|
+
a[a.exits.index(c)] = nil
|
1437
|
+
end
|
1438
|
+
if b and not rooms.member?(b)
|
1439
|
+
idx = b.exits.rindex(c)
|
1440
|
+
b[idx] = nil if idx
|
1441
|
+
end
|
1442
|
+
}
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
if @complexConnection
|
1446
|
+
@complexConnection = false
|
1447
|
+
status MSG_COMPLEX_CONNECTION_STOPPED
|
1448
|
+
end
|
1441
1449
|
|
1442
1450
|
modified = true
|
1443
1451
|
create_pathmap
|
@@ -1452,15 +1460,19 @@ class FXMap < Map
|
|
1452
1460
|
rooms, conns = _cut_selected
|
1453
1461
|
|
1454
1462
|
# Remove room exits pointing to any removed connection
|
1455
|
-
conns
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1463
|
+
if conns
|
1464
|
+
conns.each { |c|
|
1465
|
+
a = c.roomA
|
1466
|
+
b = c.roomB
|
1467
|
+
if not rooms.member?(a)
|
1468
|
+
a[a.exits.index(c)] = nil
|
1469
|
+
end
|
1470
|
+
if b and not rooms.member?(b)
|
1471
|
+
idx = b.exits.rindex(c)
|
1472
|
+
b[idx] = nil if idx
|
1473
|
+
end
|
1474
|
+
}
|
1475
|
+
end
|
1464
1476
|
|
1465
1477
|
if @complexConnection
|
1466
1478
|
@complexConnection = false
|
@@ -46,7 +46,7 @@ require 'IFMapper/FXWarningBox'
|
|
46
46
|
class FXMapperWindow < FXMainWindow
|
47
47
|
|
48
48
|
PROGRAM_NAME = "Interactive Fiction Mapper"
|
49
|
-
VERSION = '1.0.
|
49
|
+
VERSION = '1.0.9'
|
50
50
|
AUTHOR = "Gonzalo Garramuño"
|
51
51
|
|
52
52
|
@@copy_buffer = nil
|
@@ -909,6 +909,7 @@ class FXMapperWindow < FXMainWindow
|
|
909
909
|
sect.connections.each { |c|
|
910
910
|
c.selected = true
|
911
911
|
}
|
912
|
+
map.draw
|
912
913
|
end
|
913
914
|
|
914
915
|
def roomlist(sender, sel, event)
|
@@ -0,0 +1,526 @@
|
|
1
|
+
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'pdf/writer'
|
6
|
+
rescue LoadError => e
|
7
|
+
err = "PDF-Writer library not found. Please install it.\n"
|
8
|
+
if $rubygems
|
9
|
+
err += "You can usually do so if you do 'gem install pdf-writer'."
|
10
|
+
else
|
11
|
+
err += "You can download it from www.rubyforge.net."
|
12
|
+
end
|
13
|
+
raise LoadError, err
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'IFMapper/MapPrinting'
|
17
|
+
|
18
|
+
PDF_ZOOM = 0.5
|
19
|
+
PDF_ROOM_WIDTH = W * PDF_ZOOM
|
20
|
+
PDF_ROOM_HEIGHT = H * PDF_ZOOM
|
21
|
+
PDF_ROOM_WS = WS * PDF_ZOOM
|
22
|
+
PDF_ROOM_HS = HS * PDF_ZOOM
|
23
|
+
PDF_MARGIN = 20.0
|
24
|
+
|
25
|
+
#
|
26
|
+
# Open all the map class and add all pdf methods there
|
27
|
+
# Gotta love Ruby's flexibility to just inject in new methods.
|
28
|
+
#
|
29
|
+
class FXConnection
|
30
|
+
def _cvt_pt(p, opts)
|
31
|
+
x = (p[0] - WW / 2.0) / WW.to_f
|
32
|
+
y = (p[1] - HH / 2.0) / HH.to_f
|
33
|
+
x = x * opts['ww'] + opts['ws_2'] + opts['margin_2'] + opts['w'] / 2.0
|
34
|
+
y = (opts['height'] - y) * opts['hh'] + opts['hs_2'] + opts['margin_2'] + opts['hs']
|
35
|
+
return [x, y]
|
36
|
+
end
|
37
|
+
|
38
|
+
def pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
39
|
+
return if @dir == BOTH
|
40
|
+
|
41
|
+
pt1, d = _arrow_info( x1, y1, x2, y2, 0.5 )
|
42
|
+
|
43
|
+
p = []
|
44
|
+
p << PDF::Writer::PolygonPoint.new( pt1[0], pt1[1] )
|
45
|
+
p << PDF::Writer::PolygonPoint.new( pt1[0] + d[0], pt1[1] - d[1] )
|
46
|
+
p << PDF::Writer::PolygonPoint.new( pt1[0] + d[1], pt1[1] + d[0] )
|
47
|
+
pdf.fill_color Color::RGB::Black
|
48
|
+
pdf.polygon(p).fill
|
49
|
+
end
|
50
|
+
|
51
|
+
def pdf_draw_complex_as_bspline( pdf, opts )
|
52
|
+
p = []
|
53
|
+
p << _cvt_pt(@pts[0], opts)
|
54
|
+
p << p[0]
|
55
|
+
p << p[0]
|
56
|
+
@pts.each { |pt|
|
57
|
+
p << _cvt_pt(pt, opts)
|
58
|
+
}
|
59
|
+
p << p[-1]
|
60
|
+
p << p[-1]
|
61
|
+
p << p[-1]
|
62
|
+
return FXSpline::bspline(p)
|
63
|
+
end
|
64
|
+
|
65
|
+
# PRE: If it's a loop exit that comes back to the same place, let's move
|
66
|
+
# it up and right
|
67
|
+
def pdf_draw_complex_as_lines( pdf, opts )
|
68
|
+
p = []
|
69
|
+
maxy = opts['height'] * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
70
|
+
@pts.each { |pt|
|
71
|
+
if loop? == true
|
72
|
+
p << [ pt[0] * PDF_ZOOM + 10, maxy - pt[1] * PDF_ZOOM + 48 ]
|
73
|
+
else
|
74
|
+
p << [ pt[0] * PDF_ZOOM, maxy - pt[1] * PDF_ZOOM ]
|
75
|
+
end
|
76
|
+
}
|
77
|
+
return p
|
78
|
+
end
|
79
|
+
|
80
|
+
def pdf_draw_door( pdf, x1, y1, x2, y2 )
|
81
|
+
v = [ (x2-x1), (y2-y1) ]
|
82
|
+
t = 10 / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
83
|
+
v = [ v[0]*t, v[1]*t ]
|
84
|
+
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
85
|
+
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
86
|
+
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
87
|
+
if @type == LOCKED_DOOR
|
88
|
+
pdf.move_to(x1, y1)
|
89
|
+
pdf.line_to(x2, y2).stroke
|
90
|
+
else
|
91
|
+
s = PDF::Writer::StrokeStyle.new(1,
|
92
|
+
:cap => :butt,
|
93
|
+
:join => :miter,
|
94
|
+
:dash => PDF::Writer::StrokeStyle::SOLID_LINE )
|
95
|
+
pdf.stroke_style(s)
|
96
|
+
v = [ v[0] / 3, v[1] / 3]
|
97
|
+
pdf.move_to(x1 - v[0], y1 - v[1])
|
98
|
+
pdf.line_to(x1 + v[0], y1 + v[1])
|
99
|
+
pdf.line_to(x2 + v[0], y2 + v[1])
|
100
|
+
pdf.line_to(x2 - v[0], y2 - v[1])
|
101
|
+
pdf.line_to(x1 - v[0], y1 - v[1])
|
102
|
+
pdf.stroke
|
103
|
+
s = PDF::Writer::StrokeStyle.new(2,
|
104
|
+
:cap => :butt,
|
105
|
+
:join => :miter,
|
106
|
+
:dash => PDF::Writer::StrokeStyle::SOLID_LINE )
|
107
|
+
pdf.stroke_style(s)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def pdf_draw_complex( pdf, opts )
|
112
|
+
if opts['Paths as Curves']
|
113
|
+
if @room[0] == @room[1]
|
114
|
+
dirA, dirB = dirs
|
115
|
+
if dirA == dirB
|
116
|
+
p = pdf_draw_complex_as_lines( pdf, opts )
|
117
|
+
else
|
118
|
+
p = pdf_draw_complex_as_bspline( pdf, opts )
|
119
|
+
end
|
120
|
+
else
|
121
|
+
p = pdf_draw_complex_as_bspline( pdf, opts )
|
122
|
+
end
|
123
|
+
else
|
124
|
+
p = pdf_draw_complex_as_lines( pdf, opts )
|
125
|
+
end
|
126
|
+
pdf.move_to( p[0][0], p[0][1] )
|
127
|
+
p.each { |pt| pdf.line_to( pt[0], pt[1] ) }
|
128
|
+
pdf.stroke
|
129
|
+
|
130
|
+
x1, y1 = [p[0][0], p[0][1]]
|
131
|
+
x2, y2 = [p[-1][0], p[-1][1]]
|
132
|
+
pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
133
|
+
|
134
|
+
if @type == LOCKED_DOOR or @type == CLOSED_DOOR
|
135
|
+
t = p.size / 2
|
136
|
+
x1, y1 = [ p[t][0], p[t][1] ]
|
137
|
+
x2, y2 = [ p[t-2][0], p[t-2][1] ]
|
138
|
+
pdf_draw_door(pdf, x1, y1, x2, y2)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def pdf_draw_simple(pdf, opts)
|
143
|
+
return if not @room[1] # PDF does not print unfinished complex connections
|
144
|
+
|
145
|
+
dir = @room[0].exits.index(self)
|
146
|
+
x1, y1 = @room[0].pdf_corner(opts, self, dir)
|
147
|
+
x2, y2 = @room[1].pdf_corner(opts, self)
|
148
|
+
pdf.move_to(x1, y1)
|
149
|
+
pdf.line_to(x2, y2).stroke
|
150
|
+
pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
151
|
+
if @type == LOCKED_DOOR or @type == CLOSED_DOOR
|
152
|
+
pdf_draw_door(pdf, x1, y1, x2, y2)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Draw the connection text next to the arrow ('I', 'O', etc)
|
158
|
+
#
|
159
|
+
def pdf_draw_text(pdf, x, y, dir, text, arrow)
|
160
|
+
if dir == 7 or dir < 6 and dir != 1
|
161
|
+
if arrow and (dir == 0 or dir == 4)
|
162
|
+
x += 5
|
163
|
+
end
|
164
|
+
x += 2.5
|
165
|
+
elsif dir == 6 or dir == 1
|
166
|
+
x -= 7.5
|
167
|
+
end
|
168
|
+
|
169
|
+
if dir > 5 or dir < 4
|
170
|
+
if arrow and (dir == 6 or dir == 2)
|
171
|
+
y += 5
|
172
|
+
end
|
173
|
+
y += 2.5
|
174
|
+
elsif dir == 4 or dir == 5
|
175
|
+
y -= 7.5
|
176
|
+
end
|
177
|
+
|
178
|
+
font_size = 8
|
179
|
+
pdf.add_text(x, y, text, font_size)
|
180
|
+
end
|
181
|
+
|
182
|
+
def pdf_draw_exit_text(pdf, opts)
|
183
|
+
|
184
|
+
if @exitText[0] != 0
|
185
|
+
dir = @room[0].exits.index(self)
|
186
|
+
x, y = @room[0].pdf_corner(opts, self, dir)
|
187
|
+
pdf_draw_text( pdf, x, y, dir,
|
188
|
+
EXIT_TEXT[@exitText[0]], @dir == BtoA)
|
189
|
+
end
|
190
|
+
|
191
|
+
if @exitText[1] != 0
|
192
|
+
dir = @room[1].exits.rindex(self)
|
193
|
+
x, y = @room[1].pdf_corner(opts, self, dir)
|
194
|
+
pdf_draw_text( pdf, x, y, dir,
|
195
|
+
EXIT_TEXT[@exitText[1]], @dir == AtoB)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def pdf_draw(pdf, opts)
|
200
|
+
pdf_draw_exit_text(pdf, opts)
|
201
|
+
if @type == SPECIAL
|
202
|
+
s = PDF::Writer::StrokeStyle.new(2, :dash => {
|
203
|
+
:pattern => [2],
|
204
|
+
:phase => [1]
|
205
|
+
} )
|
206
|
+
else
|
207
|
+
s = PDF::Writer::StrokeStyle.new(2,
|
208
|
+
:cap => :butt,
|
209
|
+
:join => :miter,
|
210
|
+
:dash => PDF::Writer::StrokeStyle::SOLID_LINE )
|
211
|
+
end
|
212
|
+
pdf.stroke_style( s )
|
213
|
+
pdf.stroke_color Color::RGB::Black
|
214
|
+
pdf.fill_color Color::RGB::Black
|
215
|
+
if @pts.size > 0
|
216
|
+
pdf_draw_complex(pdf, opts)
|
217
|
+
else
|
218
|
+
pdf_draw_simple(pdf, opts)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
class FXRoom
|
225
|
+
def pdf_corner( opts, c, idx = nil )
|
226
|
+
x, y = _corner(c, idx)
|
227
|
+
y = -y
|
228
|
+
|
229
|
+
ww = opts['ww']
|
230
|
+
hh = opts['hh']
|
231
|
+
w = opts['w']
|
232
|
+
h = opts['h']
|
233
|
+
|
234
|
+
ry = opts['height'] - @y
|
235
|
+
x = @x * ww + opts['ws_2'] + opts['margin_2'] + x * w
|
236
|
+
y = ry * hh + opts['hs_2'] + h + opts['margin_2'] + y * h
|
237
|
+
return [x, y]
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
def pdf_draw_box( pdf, opts, idx, pdflocationnos )
|
242
|
+
x = @x * opts['ww'] + opts['ws_2'] + opts['margin_2']
|
243
|
+
y = (opts['height'] - @y) * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
244
|
+
|
245
|
+
s = PDF::Writer::StrokeStyle::DEFAULT
|
246
|
+
pdf.stroke_style( s )
|
247
|
+
|
248
|
+
if @darkness
|
249
|
+
pdf.fill_color( Color::RGB::Gray )
|
250
|
+
else
|
251
|
+
pdf.fill_color( Color::RGB::White )
|
252
|
+
end
|
253
|
+
|
254
|
+
pdf.rectangle(x, y, opts['w'], opts['h']).fill_stroke
|
255
|
+
|
256
|
+
if pdflocationnos == 1
|
257
|
+
# PRE: Draw a rectangle for the location number
|
258
|
+
pdf.rectangle((x+opts['w']-opts['w']/4), y, opts['w']/4, opts['h']/4).fill_stroke
|
259
|
+
|
260
|
+
# PRE: Pad out the number so it is three chars long
|
261
|
+
locationno = (idx+1).to_s
|
262
|
+
if (idx+1) < 10
|
263
|
+
locationno = ' '+locationno
|
264
|
+
elsif (idx+1) < 100
|
265
|
+
locationno = ' '+locationno
|
266
|
+
end
|
267
|
+
|
268
|
+
# PRE: Write the location number
|
269
|
+
pdf.fill_color(Color::RGB::Black)
|
270
|
+
pdf.add_text((x+((opts['w']/4)*3)+2), y+2, locationno, 8)
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
def pdf_draw_text( pdf, opts, x, y, text, font_size, pdflocationnos )
|
276
|
+
miny = (opts['height'] - @y) * opts['hh'] + opts['hs_2'] +
|
277
|
+
opts['margin_2']
|
278
|
+
while text != ''
|
279
|
+
# PRE: Wrap the text to avoid the location number box
|
280
|
+
if (y >= miny) and (y <= (miny+font_size)) and (pdflocationnos == 1)
|
281
|
+
wrapwidthmodifier = 15
|
282
|
+
else
|
283
|
+
wrapwidthmodifier = 2
|
284
|
+
end
|
285
|
+
text = pdf.add_text_wrap(x, y, opts['w'] - wrapwidthmodifier, text, font_size)
|
286
|
+
y -= font_size
|
287
|
+
break if y <= miny
|
288
|
+
end
|
289
|
+
return [x, y]
|
290
|
+
end
|
291
|
+
|
292
|
+
def pdf_draw_objects(pdf, opts, x, y, pdflocationnos)
|
293
|
+
font_size = 6
|
294
|
+
objs = @objects.split("\n")
|
295
|
+
objs = objs.join(', ')
|
296
|
+
return pdf_draw_text( pdf, opts, x, y, objs, font_size, pdflocationnos )
|
297
|
+
end
|
298
|
+
|
299
|
+
def pdf_draw_name(pdf, opts, pdflocationnos)
|
300
|
+
# We could also use pdf_corner(7) here
|
301
|
+
x = @x * opts['ww'] + opts['margin_2'] + opts['ws_2'] + 2
|
302
|
+
y = opts['height'] - @y
|
303
|
+
font_size = 8
|
304
|
+
y = y * opts['hh'] + opts['margin_2'] + opts['hs_2'] + opts['h'] -
|
305
|
+
(font_size + 2)
|
306
|
+
pdf.stroke_color(Color::RGB::Black)
|
307
|
+
pdf.fill_color(Color::RGB::Black)
|
308
|
+
return pdf_draw_text( pdf, opts, x, y, @name, font_size, pdflocationnos )
|
309
|
+
end
|
310
|
+
|
311
|
+
# PRE: Send through the index so we can print the location number
|
312
|
+
# along with boolean value indicating whether the user wants them
|
313
|
+
def pdf_draw( pdf, opts, idx, pdflocationnos )
|
314
|
+
pdf_draw_box( pdf, opts, idx, pdflocationnos )
|
315
|
+
x, y = pdf_draw_name( pdf, opts, pdflocationnos )
|
316
|
+
pdf_draw_objects(pdf, opts, x, y, pdflocationnos)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
|
321
|
+
|
322
|
+
class FXSection
|
323
|
+
|
324
|
+
def pdf_draw_grid(pdf, opts, w, h )
|
325
|
+
(0...w).each { |xx|
|
326
|
+
(0...h).each { |yy|
|
327
|
+
x = xx * opts['ww'] + opts['ws_2'] + opts['margin_2']
|
328
|
+
y = yy * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
329
|
+
pdf.rectangle(x, y, opts['w'], opts['h']).stroke
|
330
|
+
}
|
331
|
+
}
|
332
|
+
end
|
333
|
+
|
334
|
+
|
335
|
+
def pdf_draw_section_name( pdf, opts, px, py )
|
336
|
+
return if not @name or @name == ''
|
337
|
+
xymin, xymax = min_max_rooms
|
338
|
+
text = @name
|
339
|
+
text += " (#{px}, #{py})" if px > 0 or py > 0
|
340
|
+
y = (opts['height']) * opts['hh'] + 16
|
341
|
+
w = xymax[0]
|
342
|
+
w = opts['width'] if w > opts['width']
|
343
|
+
x = (w + 2) * opts['ww'] / 2 - text.size / 2 * 16
|
344
|
+
x = 0 if x < 0
|
345
|
+
pdf.add_text( x, y, text, 16 )
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
def pdf_draw(pdf, opts, mapname, pdflocationnos )
|
350
|
+
|
351
|
+
|
352
|
+
w, h = rooms_width_height
|
353
|
+
x, y = [0, 0]
|
354
|
+
|
355
|
+
loop do
|
356
|
+
|
357
|
+
if rotate
|
358
|
+
pdf.rotate_axis(90.0)
|
359
|
+
pdf.translate_axis( 0, -pdf.page_height )
|
360
|
+
end
|
361
|
+
|
362
|
+
# Move section to its position in page
|
363
|
+
tx1, ty1 = [@xoff * opts['ww'], @yoff * -opts['hh']]
|
364
|
+
pdf.translate_axis( tx1, ty1 )
|
365
|
+
|
366
|
+
# Use times-roman as font
|
367
|
+
pdf.select_font 'Times-Roman'
|
368
|
+
pdf.stroke_color(Color::RGB::Black)
|
369
|
+
pdf.fill_color(Color::RGB::Black)
|
370
|
+
|
371
|
+
pdf_draw_section_name( pdf, opts, x, y )
|
372
|
+
|
373
|
+
xymin, = min_max_rooms
|
374
|
+
|
375
|
+
# Move rooms, so that we don't print empty areas
|
376
|
+
tx2 = -(xymin[0]) * opts['ww'] - x * opts['ww']
|
377
|
+
ty2 = (xymin[1]) * opts['hh'] - 60 + (y - (y > 0? 1 : 0)) * opts['hh']
|
378
|
+
pdf.translate_axis( tx2, ty2 )
|
379
|
+
|
380
|
+
|
381
|
+
# For testing purposes only, draw grid of boxes
|
382
|
+
# pdf_draw_grid( pdf, opts, w, h )
|
383
|
+
@connections.each { |c|
|
384
|
+
a = c.roomA
|
385
|
+
b = c.roomB
|
386
|
+
next if a.y < y and b and b.y < y
|
387
|
+
c.pdf_draw( pdf, opts )
|
388
|
+
}
|
389
|
+
@rooms.each_with_index { |r, idx|
|
390
|
+
next if r.y < y
|
391
|
+
r.pdf_draw( pdf, opts, idx, pdflocationnos)
|
392
|
+
}
|
393
|
+
|
394
|
+
# Reset axis
|
395
|
+
pdf.translate_axis(-tx2, -ty2)
|
396
|
+
pdf.translate_axis(-tx1, -ty1)
|
397
|
+
|
398
|
+
xi = opts['width']
|
399
|
+
yi = opts['height']
|
400
|
+
if rotate
|
401
|
+
xi = (pdf.page_height / opts['ww']).to_i - 1
|
402
|
+
yi = (pdf.page_width / opts['hh']).to_i - 1
|
403
|
+
end
|
404
|
+
|
405
|
+
x += xi
|
406
|
+
if x >= w
|
407
|
+
x = 0
|
408
|
+
y += yi
|
409
|
+
break if y >= h
|
410
|
+
end
|
411
|
+
|
412
|
+
if rotate
|
413
|
+
pdf.rotate_axis(-90.0)
|
414
|
+
pdf.translate_axis( 0, pdf.page_height )
|
415
|
+
end
|
416
|
+
|
417
|
+
# We could not fit all rooms in page. Start new page
|
418
|
+
pdf.start_new_page
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
|
424
|
+
class FXMap
|
425
|
+
|
426
|
+
attr_accessor :pdfpapersize
|
427
|
+
# boolean value indicating whether the user wants to see location nos
|
428
|
+
attr_accessor :pdflocationnos
|
429
|
+
|
430
|
+
def pdf_draw_mapname( pdf, opts )
|
431
|
+
return if not @name or @name == ''
|
432
|
+
pdf.text( @name,
|
433
|
+
:font_size => 24,
|
434
|
+
:justification => :center
|
435
|
+
)
|
436
|
+
end
|
437
|
+
|
438
|
+
def pdf_draw_sections( pdf, opts )
|
439
|
+
old_section = @section
|
440
|
+
page = -1
|
441
|
+
@sections.each_with_index { |sect, idx|
|
442
|
+
if page != sect.page
|
443
|
+
page = sect.page
|
444
|
+
pdf.start_new_page if page > 1
|
445
|
+
pdf_draw_mapname( pdf, opts )
|
446
|
+
end
|
447
|
+
@section = idx
|
448
|
+
# For each page, we need to regenerate the pathmap so that complex
|
449
|
+
# paths will come out ok.
|
450
|
+
create_pathmap
|
451
|
+
# Now, we draw it
|
452
|
+
sect.pdf_draw(pdf, opts, @name, pdflocationnos)
|
453
|
+
}
|
454
|
+
|
455
|
+
# Restore original viewing page
|
456
|
+
@section = old_section
|
457
|
+
create_pathmap
|
458
|
+
end
|
459
|
+
|
460
|
+
|
461
|
+
def pdf_export(pdffile = Dir::tmpdir + "/ifmap.pdf", printer = nil)
|
462
|
+
|
463
|
+
# PRE: Let's set the PDF paper size to user's choice
|
464
|
+
paper = BOX_PDF_PAGE_SIZE_TEXT[pdfpapersize]
|
465
|
+
if printer
|
466
|
+
case printer.mediasize
|
467
|
+
when FXPrinter::MEDIA_LETTER
|
468
|
+
paper = 'LETTER'
|
469
|
+
when FXPrinter::MEDIA_LEGAL
|
470
|
+
paper = 'LEGAL'
|
471
|
+
when FXPrinter::MEDIA_A4
|
472
|
+
paper = 'A4'
|
473
|
+
when FXPrinter::MEDIA_ENVELOPE
|
474
|
+
paper = 'ENVELOPE'
|
475
|
+
when FXPrinter::MEDIA_CUSTOM
|
476
|
+
raise "Sorry, custom paper not supported"
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
# Open a new PDF writer with paper selected
|
481
|
+
# PRE: Let's also set the paper orientation based on user selection
|
482
|
+
pdf = PDF::Writer.new :paper => paper
|
483
|
+
|
484
|
+
pdf.margins_pt 0
|
485
|
+
|
486
|
+
pdf_options = @options.dup
|
487
|
+
|
488
|
+
ww = PDF_ROOM_WIDTH + PDF_ROOM_WS
|
489
|
+
hh = PDF_ROOM_HEIGHT + PDF_ROOM_HS
|
490
|
+
|
491
|
+
pdf_options.merge!(
|
492
|
+
{
|
493
|
+
'ww' => ww,
|
494
|
+
'hh' => hh,
|
495
|
+
'w' => PDF_ROOM_WIDTH,
|
496
|
+
'h' => PDF_ROOM_HEIGHT,
|
497
|
+
'ws' => PDF_ROOM_WS,
|
498
|
+
'hs' => PDF_ROOM_HS,
|
499
|
+
'ws_2' => PDF_ROOM_WS / 2.0,
|
500
|
+
'hs_2' => PDF_ROOM_HS / 2.0,
|
501
|
+
'margin' => PDF_MARGIN,
|
502
|
+
'margin_2' => PDF_MARGIN / 2.0,
|
503
|
+
'width' => (pdf.page_width / ww).to_i - 1,
|
504
|
+
'height' => (pdf.page_height / hh).to_i - 1,
|
505
|
+
}
|
506
|
+
)
|
507
|
+
|
508
|
+
|
509
|
+
begin
|
510
|
+
# See if it is possible to pack several map sections (sections) into
|
511
|
+
# a single print page.
|
512
|
+
num = pack_sections( pdf_options['width'] + 2,
|
513
|
+
pdf_options['height'] + 2 )
|
514
|
+
pdf_draw_sections(pdf, pdf_options)
|
515
|
+
if pdffile !~ /\.pdf$/
|
516
|
+
pdffile << ".pdf"
|
517
|
+
end
|
518
|
+
status "Exporting PDF file '#{pdffile}'"
|
519
|
+
pdf.save_as(pdffile)
|
520
|
+
rescue => e
|
521
|
+
p e
|
522
|
+
p e.backtrace
|
523
|
+
raise e
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|