ifmapper 0.5 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.txt +26 -0
- data/IFMapper.gemspec +1 -1
- data/icons/room_e.gif +0 -0
- data/icons/room_e.xpm +39 -0
- data/icons/room_n.gif +0 -0
- data/icons/room_n.xpm +40 -0
- data/icons/room_ne.gif +0 -0
- data/icons/room_ne.xpm +80 -0
- data/icons/room_nw.gif +0 -0
- data/icons/room_nw.xpm +80 -0
- data/icons/room_s.gif +0 -0
- data/icons/room_s.xpm +40 -0
- data/icons/room_se.gif +0 -0
- data/icons/room_se.xpm +80 -0
- data/icons/room_sw.gif +0 -0
- data/icons/room_sw.xpm +80 -0
- data/icons/room_w.gif +0 -0
- data/icons/room_w.xpm +39 -0
- data/lib/IFMapper/AStar.rb +243 -0
- data/lib/IFMapper/FXConnection.rb +101 -72
- data/lib/IFMapper/FXMap.rb +155 -230
- data/lib/IFMapper/FXMapColorBox.rb +92 -0
- data/lib/IFMapper/FXMapDialogBox.rb +83 -7
- data/lib/IFMapper/FXMapperSettings.rb +1 -0
- data/lib/IFMapper/FXMapperWindow.rb +82 -48
- data/lib/IFMapper/FXRoom.rb +43 -17
- data/lib/IFMapper/{FXPage.rb → FXSection.rb} +3 -3
- data/lib/IFMapper/{FXPageDialogBox.rb → FXSectionDialogBox.rb} +6 -6
- data/lib/IFMapper/FXSpline.rb +10 -14
- data/lib/IFMapper/IFMReader.rb +39 -31
- data/lib/IFMapper/Map.rb +42 -43
- data/lib/IFMapper/MapPrinting.rb +161 -0
- data/lib/IFMapper/PDFMapExporter.rb +128 -51
- data/lib/IFMapper/Room.rb +11 -1
- data/lib/IFMapper/{Page.rb → Section.rb} +65 -42
- metadata +34 -15
data/lib/IFMapper/FXMap.rb
CHANGED
@@ -2,20 +2,22 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
require 'IFMapper/Map'
|
5
|
-
require 'IFMapper/
|
5
|
+
require 'IFMapper/FXSection'
|
6
6
|
require 'IFMapper/FXMapDialogBox'
|
7
|
-
require 'IFMapper/
|
7
|
+
require 'IFMapper/FXSectionDialogBox'
|
8
|
+
require 'IFMapper/AStar'
|
8
9
|
|
9
10
|
|
10
11
|
class FXMap < Map
|
11
12
|
FILE_FORMAT_VERSION = 1 # Upgrade this if incompatible changes are made
|
12
|
-
# in the class so that file loading of old files
|
13
|
-
# be checked against.
|
13
|
+
# in the class so that file loading of old files
|
14
|
+
# can still be checked against.
|
14
15
|
|
15
16
|
attr_reader :zoom # Current zooming factor
|
16
17
|
attr_accessor :filename # Filename of current map (if any)
|
17
18
|
attr_reader :modified # Was map modified since being loaded?
|
18
|
-
attr_accessor :navigation # Map is navigation mode (no new nodes can be
|
19
|
+
attr_accessor :navigation # Map is navigation mode (no new nodes can be
|
20
|
+
# created)
|
19
21
|
attr_accessor :options # Map options
|
20
22
|
attr_reader :window # Fox Window for this map
|
21
23
|
attr :version # file format version
|
@@ -30,7 +32,14 @@ class FXMap < Map
|
|
30
32
|
|
31
33
|
@@cursor_arrow = nil
|
32
34
|
@@cursor_cross = nil
|
33
|
-
@@
|
35
|
+
@@cursor_n = nil
|
36
|
+
@@cursor_ne = nil
|
37
|
+
@@cursor_e = nil
|
38
|
+
@@cursor_se = nil
|
39
|
+
@@cursor_s = nil
|
40
|
+
@@cursor_sw = nil
|
41
|
+
@@cursor_w = nil
|
42
|
+
@@cursor_nw = nil
|
34
43
|
|
35
44
|
|
36
45
|
def _changed
|
@@ -39,21 +48,23 @@ class FXMap < Map
|
|
39
48
|
draw
|
40
49
|
end
|
41
50
|
|
42
|
-
def
|
51
|
+
def section=(x)
|
43
52
|
super
|
44
53
|
@complexConnection = false
|
45
|
-
|
46
|
-
|
54
|
+
if @window.shown?
|
55
|
+
create_pathmap
|
56
|
+
update_title
|
57
|
+
end
|
47
58
|
end
|
48
59
|
|
49
60
|
|
50
|
-
def
|
51
|
-
self.
|
61
|
+
def previous_section
|
62
|
+
self.section = @section - 1
|
52
63
|
_changed
|
53
64
|
end
|
54
65
|
|
55
|
-
def
|
56
|
-
self.
|
66
|
+
def next_section
|
67
|
+
self.section = @section + 1
|
57
68
|
_changed
|
58
69
|
end
|
59
70
|
|
@@ -62,22 +73,22 @@ class FXMap < Map
|
|
62
73
|
_changed
|
63
74
|
end
|
64
75
|
|
65
|
-
def
|
66
|
-
@
|
76
|
+
def rename_section
|
77
|
+
@sections[@section].properties(self)
|
67
78
|
modified = true
|
68
79
|
end
|
69
80
|
|
70
|
-
def
|
71
|
-
w = FXWarningBox.new(@window, "Are you sure you want to delete this
|
81
|
+
def delete_section
|
82
|
+
w = FXWarningBox.new(@window, "Are you sure you want to delete this section?")
|
72
83
|
return if w.execute == 0
|
73
84
|
|
74
|
-
|
85
|
+
delete_section_at(@section)
|
75
86
|
modified = true
|
76
87
|
end
|
77
88
|
|
78
|
-
def
|
79
|
-
@
|
80
|
-
@
|
89
|
+
def new_section
|
90
|
+
@sections.push( FXSection.new )
|
91
|
+
@section = @sections.size - 1
|
81
92
|
end
|
82
93
|
|
83
94
|
#
|
@@ -85,11 +96,12 @@ class FXMap < Map
|
|
85
96
|
# very simple ascii representation.
|
86
97
|
#
|
87
98
|
def dump_pathmap
|
88
|
-
s = ' ' * @width + "\n"
|
99
|
+
s = ' ' + ' ' * @width + "\n"
|
89
100
|
m = s * @height
|
90
101
|
(0...@width).each { |x|
|
91
102
|
(0...@height).each { |y|
|
92
|
-
|
103
|
+
m[y * (@width+2)] = (y % 10).to_s
|
104
|
+
loc = y * (@width+2) + x + 1
|
93
105
|
if @pmap[x][y].kind_of?(Connection)
|
94
106
|
m[loc] = '-'
|
95
107
|
elsif @pmap[x][y].kind_of?(Room)
|
@@ -97,6 +109,7 @@ class FXMap < Map
|
|
97
109
|
end
|
98
110
|
}
|
99
111
|
}
|
112
|
+
puts ' 0123456789' * (@width/10)
|
100
113
|
puts m
|
101
114
|
end
|
102
115
|
|
@@ -120,9 +133,9 @@ class FXMap < Map
|
|
120
133
|
# First, create an empty grid of width x height
|
121
134
|
empty_pathmap # Hmm... needed? Probably not.
|
122
135
|
# Then, fill it in with all rooms...
|
123
|
-
@
|
136
|
+
@sections[@section].rooms.each { |r| @pmap[r.x][r.y] = r }
|
124
137
|
# And following, add all paths
|
125
|
-
@
|
138
|
+
@sections[@section].connections.each { |c| path_find(c) }
|
126
139
|
end
|
127
140
|
|
128
141
|
#
|
@@ -136,7 +149,6 @@ class FXMap < Map
|
|
136
149
|
# Remove a connection from map, since path creation failed.
|
137
150
|
#
|
138
151
|
def remove_connection(c)
|
139
|
-
clean_path(c)
|
140
152
|
c.failed = true
|
141
153
|
status "Path for connection #{c} is blocked."
|
142
154
|
end
|
@@ -188,121 +200,39 @@ class FXMap < Map
|
|
188
200
|
return true
|
189
201
|
end
|
190
202
|
|
191
|
-
|
203
|
+
# Now check if start or goal are fully blocked. If so,
|
204
|
+
# fail quickly
|
192
205
|
if pA[0] < 0 or pA[0] >= @width or
|
193
206
|
pB[0] < 0 or pB[0] >= @width or
|
194
207
|
pA[1] < 0 or pA[1] >= @height or
|
195
|
-
pB[1] < 0 or pB[1] >= @height
|
208
|
+
pB[1] < 0 or pB[1] >= @height or
|
209
|
+
@pmap[pA[0]][pA[1]].kind_of?(Room) or
|
210
|
+
@pmap[pB[0]][pB[1]].kind_of?(Room)
|
196
211
|
remove_connection(c)
|
197
212
|
return false
|
198
213
|
end
|
199
214
|
|
215
|
+
# No, okay, we need to do true A* path finding
|
200
216
|
c.failed = false
|
217
|
+
aStar = AStar.new
|
218
|
+
MapNode::map(@pmap)
|
219
|
+
start = MapNode.new( pA[0], pA[1] )
|
220
|
+
goal = MapNode.new( pB[0], pB[1] )
|
221
|
+
aStar.goals( start, goal )
|
222
|
+
while aStar.search_step == AStar::SEARCH_STATE_SEARCHING
|
223
|
+
end
|
201
224
|
|
202
|
-
#
|
203
|
-
|
204
|
-
# That is, we always try to have no paths crossing each other.
|
205
|
-
#
|
206
|
-
# If this fails, we try a second time, but we try to avoid just
|
207
|
-
# rooms. In this second attempt, paths are allowed to intercross.
|
208
|
-
#
|
209
|
-
pt = pA.dup
|
210
|
-
2.times { |try|
|
211
|
-
c.gpts = []
|
212
|
-
|
213
|
-
if try == 0
|
214
|
-
next if @pmap[pA[0]][pA[1]] or @pmap[pB[0]][pB[1]] # try again
|
215
|
-
else
|
216
|
-
if @pmap[pA[0]][pA[1]].kind_of?(Room) or
|
217
|
-
@pmap[pB[0]][pB[1]].kind_of?(Room)
|
218
|
-
remove_connection(c)
|
219
|
-
return false
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
# Okay, now we begin the real path algorithm...
|
224
|
-
# Add first point...
|
225
|
-
add_path_pt(c, pA[0], pA[1])
|
226
|
-
|
227
|
-
pt = pA.dup
|
228
|
-
|
229
|
-
# Okay, now we begin a simple A* path algorithm.
|
230
|
-
while pt[0] != pB[0] or pt[1] != pB[1]
|
231
|
-
# From point pt, get a list of free nodes, by looking all around it.
|
232
|
-
pts = []
|
233
|
-
FXRoom::DIR_TO_VECTOR.each_value { |d|
|
234
|
-
n = pt.dup
|
235
|
-
n[0] += d[0]
|
236
|
-
n[1] += d[1]
|
237
|
-
# Don't add point to list if we go out of map
|
238
|
-
if n[0] < 0 or n[0] >= @width or
|
239
|
-
n[1] < 0 or n[1] >= @height
|
240
|
-
next
|
241
|
-
end
|
242
|
-
|
243
|
-
# Now, check if pmap is an empty node.
|
244
|
-
if try == 1
|
245
|
-
next if @pmap[n[0]][n[1]].kind_of?(Room) or
|
246
|
-
@pmap[n[0]][n[1]] == c
|
247
|
-
else
|
248
|
-
next if @pmap[n[0]][n[1]]
|
249
|
-
end
|
250
|
-
|
251
|
-
# Ok, we do have an empty node. Add to list.
|
252
|
-
pts.push(n)
|
253
|
-
}
|
254
|
-
|
255
|
-
break if pts.empty?
|
256
|
-
|
257
|
-
# Okay, from all possible nodes, calculate best one, using
|
258
|
-
# the formula:
|
259
|
-
# F = G + H
|
260
|
-
# where G = movement cost to move from point to other point
|
261
|
-
# (10 or 14, depending if move is straight or diagonal)
|
262
|
-
# H = cost of square to shorten distance to destination.
|
263
|
-
# (heuristic, in this case using Manhattan distance)
|
264
|
-
# Next move is the grid node with lowest F cost.
|
265
|
-
|
266
|
-
f = []
|
267
|
-
pts.each { |x|
|
268
|
-
dx = x[0] - pt[0]
|
269
|
-
dy = x[1] - pt[1]
|
270
|
-
g = 10 # straight move G cost = 10 (ie. prefer straight moves)
|
271
|
-
if dx.abs + dy.abs > 1
|
272
|
-
g = 14 # diagonal move G cost = 14
|
273
|
-
end
|
274
|
-
|
275
|
-
dx = pB[0] - x[0]
|
276
|
-
dy = pB[1] - x[1]
|
277
|
-
h = dx * dx + dy * dy
|
278
|
-
|
279
|
-
f.push( h + g )
|
280
|
-
}
|
281
|
-
|
282
|
-
idx = f.index(f.min)
|
283
|
-
pt = pts[idx]
|
284
|
-
add_path_pt(c, pt[0], pt[1])
|
285
|
-
end # while
|
286
|
-
|
287
|
-
|
288
|
-
# Are we really there?
|
289
|
-
if pt[0] != pB[0] or pt[1] != pB[1]
|
290
|
-
# No, we must have failed...
|
291
|
-
clean_path(c)
|
292
|
-
c.gpts = []
|
293
|
-
next # go for next try
|
294
|
-
else
|
295
|
-
break
|
296
|
-
end
|
297
|
-
}
|
298
|
-
|
299
|
-
# If still not there, we cannot connect path, exit gracefully
|
300
|
-
if pt[0] != pB[0] or pt[1] != pB[1]
|
301
|
-
# If on second try, remove connection as invalid.
|
225
|
+
# Oops, AStar failed. Not a clean path
|
226
|
+
if aStar.state == AStar::SEARCH_STATE_FAILED
|
302
227
|
remove_connection(c)
|
303
228
|
return false
|
304
229
|
end
|
305
230
|
|
231
|
+
# We succeeded. Get the path
|
232
|
+
c.failed = false
|
233
|
+
c.gpts = aStar.path
|
234
|
+
# Put path in pathmap so subsequent paths will avoid crossing it.
|
235
|
+
c.gpts.each { |p| @pmap[p[0]][p[1]] = c }
|
306
236
|
|
307
237
|
# Okay, we have a valid path.
|
308
238
|
# Create real path in display coordinates now...
|
@@ -317,7 +247,6 @@ class FXMap < Map
|
|
317
247
|
}
|
318
248
|
# And end with b's corner
|
319
249
|
pt = b.corner(c, 1, dirB)
|
320
|
-
c.failed = false
|
321
250
|
return c.pts.push([pt[0], pt[1]])
|
322
251
|
end
|
323
252
|
|
@@ -333,19 +262,10 @@ class FXMap < Map
|
|
333
262
|
# Used for loading class with Marshal
|
334
263
|
#
|
335
264
|
def marshal_load(variables)
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
# copy(tmpmap)
|
341
|
-
# @navigation = variables[2]
|
342
|
-
# @options = variables[3] if variables[3]
|
343
|
-
# else
|
344
|
-
@zoom = variables.shift
|
345
|
-
@navigation = variables.shift
|
346
|
-
@options = variables.shift
|
347
|
-
super
|
348
|
-
# end
|
265
|
+
@zoom = variables.shift
|
266
|
+
@navigation = variables.shift
|
267
|
+
@options = variables.shift
|
268
|
+
super
|
349
269
|
@modified = false
|
350
270
|
end
|
351
271
|
|
@@ -376,7 +296,7 @@ class FXMap < Map
|
|
376
296
|
@modified = true
|
377
297
|
x = x / WW
|
378
298
|
y = y / HH
|
379
|
-
r = @
|
299
|
+
r = @sections[@section].new_room(x, y)
|
380
300
|
@pmap[x][y] = r
|
381
301
|
|
382
302
|
buf = FXMapperWindow::copy_buffer()
|
@@ -386,7 +306,7 @@ class FXMap < Map
|
|
386
306
|
|
387
307
|
if @options['Edit on Creation']
|
388
308
|
if not r.modal_properties(self)
|
389
|
-
@
|
309
|
+
@sections[@section].delete_room(r)
|
390
310
|
@pmap[x][y] = nil
|
391
311
|
return nil
|
392
312
|
end
|
@@ -434,7 +354,7 @@ class FXMap < Map
|
|
434
354
|
return @pmap[xx][yy]
|
435
355
|
else
|
436
356
|
# Possible arrow
|
437
|
-
@
|
357
|
+
@sections[@section].connections.each { |c|
|
438
358
|
a = c.roomA
|
439
359
|
b = c.roomB
|
440
360
|
next if not b # Complex connection in progress
|
@@ -497,8 +417,8 @@ class FXMap < Map
|
|
497
417
|
title << " [Read Only]"
|
498
418
|
end
|
499
419
|
title << " Zoom: %.3f" % @zoom
|
500
|
-
title << "
|
501
|
-
title << " #{@
|
420
|
+
title << " Section #{@section+1} of #{@sections.size}"
|
421
|
+
title << " #{@sections[@section].name}"
|
502
422
|
@window.title = title
|
503
423
|
end
|
504
424
|
|
@@ -650,14 +570,14 @@ class FXMap < Map
|
|
650
570
|
c = new_connection( roomA, exitA, nil )
|
651
571
|
status "Click on other room exit in complex connection."
|
652
572
|
else
|
653
|
-
@
|
573
|
+
@sections[@section].delete_connection_at(-1)
|
654
574
|
c = new_connection( @complexConnection[0],
|
655
575
|
@complexConnection[1], roomA, exitA )
|
656
576
|
if path_find(c) # Do A* path finding to connect both exits
|
657
577
|
@modified = true
|
658
578
|
status "Complex connection done."
|
659
579
|
else
|
660
|
-
@
|
580
|
+
@sections[@section].delete_connection_at(-1)
|
661
581
|
end
|
662
582
|
draw
|
663
583
|
@complexConnection = nil
|
@@ -720,18 +640,6 @@ class FXMap < Map
|
|
720
640
|
end
|
721
641
|
end
|
722
642
|
|
723
|
-
ZOOM_SEQUENCE = [
|
724
|
-
0.4,
|
725
|
-
0.5,
|
726
|
-
0.6,
|
727
|
-
0.7,
|
728
|
-
0.8,
|
729
|
-
0.9,
|
730
|
-
1.0,
|
731
|
-
1.1,
|
732
|
-
1.2,
|
733
|
-
]
|
734
|
-
|
735
643
|
# Self-explanatory.
|
736
644
|
def zoom_out
|
737
645
|
if @zoom > 0.25
|
@@ -754,13 +662,45 @@ class FXMap < Map
|
|
754
662
|
s.normalText = s.text = msg
|
755
663
|
end
|
756
664
|
|
665
|
+
def cursor_switch(x, y)
|
666
|
+
if not @options['Use Room Cursor']
|
667
|
+
@canvas.defaultCursor = @@cursor_arrow
|
668
|
+
return
|
669
|
+
end
|
670
|
+
q = get_quadrant(x, y)
|
671
|
+
case q
|
672
|
+
when 0
|
673
|
+
@canvas.defaultCursor = @@cursor_n
|
674
|
+
when 1
|
675
|
+
@canvas.defaultCursor = @@cursor_ne
|
676
|
+
when 2
|
677
|
+
@canvas.defaultCursor = @@cursor_e
|
678
|
+
when 3
|
679
|
+
@canvas.defaultCursor = @@cursor_se
|
680
|
+
when 4
|
681
|
+
@canvas.defaultCursor = @@cursor_s
|
682
|
+
when 5
|
683
|
+
@canvas.defaultCursor = @@cursor_sw
|
684
|
+
when 6
|
685
|
+
@canvas.defaultCursor = @@cursor_w
|
686
|
+
when 7
|
687
|
+
@canvas.defaultCursor = @@cursor_nw
|
688
|
+
else
|
689
|
+
@canvas.defaultCursor = @@cursor_arrow
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
757
693
|
#
|
758
694
|
# Show some help status in status line based on cursor position
|
759
695
|
#
|
760
696
|
def help_cb(sender, sel, event)
|
761
|
-
|
697
|
+
|
762
698
|
x = (event.last_x / @zoom).to_i
|
763
699
|
y = (event.last_y / @zoom).to_i
|
700
|
+
if @complexConnection
|
701
|
+
cursor_switch(x,y)
|
702
|
+
return
|
703
|
+
end
|
764
704
|
|
765
705
|
sel = to_object(x, y)
|
766
706
|
if sel
|
@@ -775,14 +715,7 @@ class FXMap < Map
|
|
775
715
|
@canvas.defaultCursor = @@cursor_cross
|
776
716
|
status "Click to create new room."
|
777
717
|
else
|
778
|
-
|
779
|
-
if q == 0 or q == 4
|
780
|
-
@canvas.defaultCursor = @@cursor_updown
|
781
|
-
elsif q == 2 or q == 6
|
782
|
-
@canvas.defaultCursor = @@cursor_leftright
|
783
|
-
else
|
784
|
-
@canvas.defaultCursor = @@cursor_arrow
|
785
|
-
end
|
718
|
+
cursor_switch(x, y)
|
786
719
|
status "Click to create new connection."
|
787
720
|
end
|
788
721
|
end
|
@@ -858,7 +791,7 @@ class FXMap < Map
|
|
858
791
|
x2 = (x2 / WW).ceil
|
859
792
|
y2 = (y2 / HH).ceil
|
860
793
|
|
861
|
-
@
|
794
|
+
@sections[@section].rooms.each { |r|
|
862
795
|
if r.x >= x1 and r.x <= x2 and
|
863
796
|
r.y >= y1 and r.y <= y2
|
864
797
|
r.selected = true
|
@@ -913,8 +846,8 @@ class FXMap < Map
|
|
913
846
|
# Clear rooms/connections selected
|
914
847
|
#
|
915
848
|
def clear_selection
|
916
|
-
@
|
917
|
-
@
|
849
|
+
@sections[@section].rooms.each { |r| r.selected = false }
|
850
|
+
@sections[@section].connections.each { |r| r.selected = false }
|
918
851
|
end
|
919
852
|
|
920
853
|
#
|
@@ -955,7 +888,7 @@ class FXMap < Map
|
|
955
888
|
if click_type(x, y)
|
956
889
|
return if @complexConnection
|
957
890
|
# Add a new room
|
958
|
-
roomB = @
|
891
|
+
roomB = @sections[@section].rooms[-1]
|
959
892
|
roomA = new_xy_room( x, y )
|
960
893
|
if roomB and roomA and @options['Automatic Connection']
|
961
894
|
# check to see if rooms are next to each other
|
@@ -1002,7 +935,7 @@ class FXMap < Map
|
|
1002
935
|
selection.selected = true
|
1003
936
|
end
|
1004
937
|
end
|
1005
|
-
draw(event)
|
938
|
+
draw(sender, sel, event)
|
1006
939
|
end
|
1007
940
|
|
1008
941
|
|
@@ -1071,6 +1004,19 @@ class FXMap < Map
|
|
1071
1004
|
|
1072
1005
|
|
1073
1006
|
def _make_cursors
|
1007
|
+
pix = []
|
1008
|
+
32.times { 32.times { pix << 255 << 255 << 255 << 255 } }
|
1009
|
+
pix = pix.pack('c*')
|
1010
|
+
['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each { |d|
|
1011
|
+
eval(<<-"EOF")
|
1012
|
+
@@cursor_#{d} = FXGIFCursor.new(@window.getApp, pix)
|
1013
|
+
FXFileStream.open('icons/room_#{d}.gif', FXStreamLoad) { |stream|
|
1014
|
+
@@cursor_#{d}.loadPixels(stream)
|
1015
|
+
}
|
1016
|
+
@@cursor_#{d}.create
|
1017
|
+
EOF
|
1018
|
+
}
|
1019
|
+
|
1074
1020
|
@@cursor_move = FXCursor.new(@window.getApp, CURSOR_MOVE)
|
1075
1021
|
@@cursor_move.create
|
1076
1022
|
|
@@ -1079,12 +1025,6 @@ class FXMap < Map
|
|
1079
1025
|
|
1080
1026
|
@@cursor_cross = FXCursor.new(@window.getApp, CURSOR_CROSS)
|
1081
1027
|
@@cursor_cross.create
|
1082
|
-
|
1083
|
-
@@cursor_updown = FXCursor.new(@window.getApp, CURSOR_UPDOWN)
|
1084
|
-
@@cursor_updown.create
|
1085
|
-
|
1086
|
-
@@cursor_leftright = FXCursor.new(@window.getApp, CURSOR_LEFTRIGHT)
|
1087
|
-
@@cursor_leftright.create
|
1088
1028
|
end
|
1089
1029
|
|
1090
1030
|
def _make_widgets
|
@@ -1107,10 +1047,8 @@ class FXMap < Map
|
|
1107
1047
|
LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|
|
1108
1048
|
LAYOUT_TOP|LAYOUT_LEFT,
|
1109
1049
|
0, 0, width, height)
|
1110
|
-
|
1111
|
-
@canvas.connect(SEL_PAINT
|
1112
|
-
draw(event)
|
1113
|
-
end
|
1050
|
+
@dirty = true
|
1051
|
+
@canvas.connect(SEL_PAINT, method(:draw))
|
1114
1052
|
@canvas.backColor = @options['BG Color']
|
1115
1053
|
|
1116
1054
|
@canvas.connect(SEL_MOUSEWHEEL, method(:mousewheel_cb))
|
@@ -1134,7 +1072,7 @@ class FXMap < Map
|
|
1134
1072
|
_make_widgets
|
1135
1073
|
end
|
1136
1074
|
empty_pathmap
|
1137
|
-
self.zoom =
|
1075
|
+
self.zoom = 0.8
|
1138
1076
|
end
|
1139
1077
|
|
1140
1078
|
|
@@ -1142,15 +1080,15 @@ class FXMap < Map
|
|
1142
1080
|
# Handle deleting selected rooms and/or connections
|
1143
1081
|
#
|
1144
1082
|
def delete_selected
|
1145
|
-
rooms = @
|
1146
|
-
conns = @
|
1083
|
+
rooms = @sections[@section].rooms.find_all { |r| r.selected }
|
1084
|
+
conns = @sections[@section].connections.find_all { |c| c.selected }
|
1147
1085
|
############################
|
1148
1086
|
# First, handle rooms...
|
1149
1087
|
############################
|
1150
1088
|
# Remove rooms from path map
|
1151
1089
|
rooms.each { |r| @pmap[r.x][r.y] = nil }
|
1152
|
-
# Remove rooms from current
|
1153
|
-
@
|
1090
|
+
# Remove rooms from current section in map
|
1091
|
+
@sections[@section].rooms -= rooms
|
1154
1092
|
# Add any connections pointing to removed rooms as connection to remove
|
1155
1093
|
rooms.each { |r|
|
1156
1094
|
conns += r.exits.find_all { |e| e != nil }
|
@@ -1163,8 +1101,8 @@ class FXMap < Map
|
|
1163
1101
|
|
1164
1102
|
# Remove connections from path map
|
1165
1103
|
conns.each { |c| clean_path(c) }
|
1166
|
-
# Remove connections from current
|
1167
|
-
@
|
1104
|
+
# Remove connections from current section in map
|
1105
|
+
@sections[@section].connections -= conns
|
1168
1106
|
# Remove room exits pointing to any removed connection
|
1169
1107
|
conns.each { |c|
|
1170
1108
|
a = c.roomA
|
@@ -1225,24 +1163,15 @@ class FXMap < Map
|
|
1225
1163
|
# Find and update all paths in path map for a room
|
1226
1164
|
#
|
1227
1165
|
def update_exits(selection)
|
1228
|
-
# We have to path_find all connections in the same order
|
1229
|
-
# as they are stored in map, and not in how they are in the room
|
1230
|
-
# so that there is consistency in path finding
|
1231
|
-
# conns = []
|
1232
|
-
# selection.each { |room|
|
1233
|
-
# room.exits.each { |c|
|
1234
|
-
# conns << c
|
1235
|
-
# }
|
1236
|
-
# }
|
1237
|
-
|
1238
|
-
# @pages[@page].connections.each { |c|
|
1239
|
-
# next if not conns.include?(c)
|
1240
|
-
# path_find(c)
|
1241
|
-
# }
|
1242
1166
|
create_pathmap
|
1243
1167
|
@modified = true
|
1244
1168
|
end
|
1245
1169
|
|
1170
|
+
def navigation_warning
|
1171
|
+
w = FXWarningBox.new(@window, "Map is in Read Only Mode. Go to Map Information to change this.")
|
1172
|
+
w.execute
|
1173
|
+
end
|
1174
|
+
|
1246
1175
|
#
|
1247
1176
|
# Handle a keypress
|
1248
1177
|
#
|
@@ -1251,14 +1180,14 @@ class FXMap < Map
|
|
1251
1180
|
when KEY_Escape
|
1252
1181
|
if @complexConnection
|
1253
1182
|
if @complexConnection.kind_of?(Array)
|
1254
|
-
@
|
1183
|
+
@sections[@section].delete_connection_at(-1)
|
1255
1184
|
status "Complex connection aborted."
|
1256
1185
|
draw
|
1257
1186
|
end
|
1258
1187
|
@complexConnection = false
|
1259
1188
|
end
|
1260
1189
|
when KEY_BackSpace, KEY_Delete
|
1261
|
-
return if @navigation
|
1190
|
+
return navigation_warning if @navigation
|
1262
1191
|
delete_selected
|
1263
1192
|
when KEY_c
|
1264
1193
|
if event.state & CONTROLMASK != 0
|
@@ -1272,7 +1201,7 @@ class FXMap < Map
|
|
1272
1201
|
draw
|
1273
1202
|
end
|
1274
1203
|
when KEY_x
|
1275
|
-
return if @navigation
|
1204
|
+
return navigation_warning if @navigation
|
1276
1205
|
if event.state & CONTROLMASK != 0
|
1277
1206
|
FXMapperWindow::cut_selected(self)
|
1278
1207
|
@modified = true
|
@@ -1281,14 +1210,13 @@ class FXMap < Map
|
|
1281
1210
|
complex_connection
|
1282
1211
|
end
|
1283
1212
|
when KEY_Up
|
1284
|
-
return if @navigation
|
1285
|
-
selection = @
|
1213
|
+
return navigation_warning if @navigation
|
1214
|
+
selection = @sections[@section].rooms.find_all { |r| r.selected }
|
1286
1215
|
return if selection.empty?
|
1287
1216
|
clean_room_selection(selection)
|
1288
1217
|
# Check that all nodes can be moved up
|
1289
1218
|
selection.each { |r|
|
1290
|
-
|
1291
|
-
if r.y == 0 or n.kind_of?(Room)
|
1219
|
+
if r.y == 0 or @pmap[r.x][r.y-1].kind_of?(Room)
|
1292
1220
|
store_room_selection(selection)
|
1293
1221
|
status "Cannot move selection up."
|
1294
1222
|
return
|
@@ -1301,14 +1229,13 @@ class FXMap < Map
|
|
1301
1229
|
update_exits(selection)
|
1302
1230
|
draw
|
1303
1231
|
when KEY_Down
|
1304
|
-
return if @navigation
|
1305
|
-
selection = @
|
1232
|
+
return navigation_warning if @navigation
|
1233
|
+
selection = @sections[@section].rooms.find_all { |r| r.selected }
|
1306
1234
|
return if selection.empty?
|
1307
1235
|
clean_room_selection(selection)
|
1308
1236
|
# Check that all nodes can be moved up
|
1309
1237
|
selection.each { |r|
|
1310
|
-
|
1311
|
-
if r.y+1 == @height or n.kind_of?(Room)
|
1238
|
+
if r.y+1 == @height or @pmap[r.x][r.y+1].kind_of?(Room)
|
1312
1239
|
store_room_selection(selection)
|
1313
1240
|
status "Cannot move selection down."
|
1314
1241
|
return
|
@@ -1321,14 +1248,13 @@ class FXMap < Map
|
|
1321
1248
|
update_exits(selection)
|
1322
1249
|
draw
|
1323
1250
|
when KEY_Left
|
1324
|
-
return if @navigation
|
1325
|
-
selection = @
|
1251
|
+
return navigation_warning if @navigation
|
1252
|
+
selection = @sections[@section].rooms.find_all { |r| r.selected }
|
1326
1253
|
return if selection.empty?
|
1327
1254
|
# Check that all nodes can be moved up
|
1328
1255
|
clean_room_selection(selection)
|
1329
1256
|
selection.each { |r|
|
1330
|
-
|
1331
|
-
if r.x == 0 or n.kind_of?(Room)
|
1257
|
+
if r.x == 0 or @pmap[r.x-1][r.y].kind_of?(Room)
|
1332
1258
|
store_room_selection(selection)
|
1333
1259
|
status "Cannot move selection left."
|
1334
1260
|
return
|
@@ -1341,14 +1267,13 @@ class FXMap < Map
|
|
1341
1267
|
update_exits(selection)
|
1342
1268
|
draw
|
1343
1269
|
when KEY_Right
|
1344
|
-
return if @navigation
|
1345
|
-
selection = @
|
1270
|
+
return navigation_warning if @navigation
|
1271
|
+
selection = @sections[@section].rooms.find_all { |r| r.selected }
|
1346
1272
|
return if selection.empty?
|
1347
1273
|
# Check that all nodes can be moved up
|
1348
1274
|
clean_room_selection(selection)
|
1349
1275
|
selection.each { |r|
|
1350
|
-
|
1351
|
-
if r.x+1 == @width or n.kind_of?(Room)
|
1276
|
+
if r.x+1 == @width or @pmap[r.x+1][r.y].kind_of?(Room)
|
1352
1277
|
store_room_selection(selection)
|
1353
1278
|
status "Cannot move selection right."
|
1354
1279
|
return
|
@@ -1486,7 +1411,7 @@ class FXMap < Map
|
|
1486
1411
|
# Clean background to solid color
|
1487
1412
|
#
|
1488
1413
|
def draw_background(dc, event = nil)
|
1489
|
-
dc.foreground = @
|
1414
|
+
dc.foreground = @options['BG Color']
|
1490
1415
|
|
1491
1416
|
if event
|
1492
1417
|
dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h)
|
@@ -1502,7 +1427,7 @@ class FXMap < Map
|
|
1502
1427
|
dc.lineStyle = LINE_SOLID
|
1503
1428
|
dc.lineWidth = 3 * @zoom
|
1504
1429
|
dc.lineWidth = 3 if dc.lineWidth < 3
|
1505
|
-
@
|
1430
|
+
@sections[@section].connections.each { |c| c.draw(dc, @zoom, @options) }
|
1506
1431
|
end
|
1507
1432
|
|
1508
1433
|
#
|
@@ -1512,7 +1437,7 @@ class FXMap < Map
|
|
1512
1437
|
data = { }
|
1513
1438
|
data['font'] = @font
|
1514
1439
|
data['objfont'] = @objfont
|
1515
|
-
@
|
1440
|
+
@sections[@section].rooms.each_with_index { |room, idx|
|
1516
1441
|
room.draw(dc, @zoom, idx, @options, data)
|
1517
1442
|
}
|
1518
1443
|
end
|
@@ -1526,7 +1451,7 @@ class FXMap < Map
|
|
1526
1451
|
#
|
1527
1452
|
# Draw map
|
1528
1453
|
#
|
1529
|
-
def draw(event = nil)
|
1454
|
+
def draw(sender = nil, sel = nil, event = nil)
|
1530
1455
|
pos = @scrollwindow.position
|
1531
1456
|
w = @scrollwindow.getViewportWidth
|
1532
1457
|
h = @scrollwindow.getViewportHeight
|
@@ -1561,7 +1486,7 @@ class FXMap < Map
|
|
1561
1486
|
def _save
|
1562
1487
|
if @complexConnection
|
1563
1488
|
# If we have an incomplete connection, remove it
|
1564
|
-
@
|
1489
|
+
@sections[@section].delete_connection_at(-1)
|
1565
1490
|
end
|
1566
1491
|
|
1567
1492
|
if @filename !~ /\.map$/i
|