ifmapper 0.6 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+
2
+ class FXDCPrint
3
+ alias :old_font= :font=
4
+ alias :old_font :font
5
+
6
+ def font
7
+ return @f
8
+ end
9
+
10
+ def font=(x)
11
+ old_font=(x)
12
+ @f = x
13
+ end
14
+
15
+ end
@@ -41,13 +41,16 @@ class FXMap < Map
41
41
  @@cursor_w = nil
42
42
  @@cursor_nw = nil
43
43
 
44
-
44
+
45
45
  def _changed
46
46
  create_pathmap
47
47
  update_title
48
48
  draw
49
49
  end
50
50
 
51
+ #
52
+ # Jump to a certain section #
53
+ #
51
54
  def section=(x)
52
55
  super
53
56
  @complexConnection = false
@@ -57,28 +60,43 @@ class FXMap < Map
57
60
  end
58
61
  end
59
62
 
60
-
63
+ #
64
+ # Go to previous section (if any)
65
+ #
61
66
  def previous_section
62
67
  self.section = @section - 1
63
68
  _changed
64
69
  end
65
70
 
71
+ #
72
+ # Go to next section (if any)
73
+ #
66
74
  def next_section
67
75
  self.section = @section + 1
68
76
  _changed
69
77
  end
70
78
 
79
+ #
80
+ # Map has been modified. Update also pathmap.
81
+ #
71
82
  def modified=(x)
72
83
  @modified = true
73
84
  _changed
74
85
  end
75
86
 
87
+ #
88
+ # Popup the section properties to allow renaming it
89
+ #
76
90
  def rename_section
77
91
  @sections[@section].properties(self)
78
92
  modified = true
79
93
  end
80
94
 
95
+ #
96
+ # Delete current section from map
97
+ #
81
98
  def delete_section
99
+ return navigation_warning if @navigation
82
100
  w = FXWarningBox.new(@window, "Are you sure you want to delete this section?")
83
101
  return if w.execute == 0
84
102
 
@@ -86,7 +104,11 @@ class FXMap < Map
86
104
  modified = true
87
105
  end
88
106
 
89
- def new_section
107
+ #
108
+ # Add a new section to map and make it current
109
+ #
110
+ def new_section
111
+ return navigation_warning if @navigation
90
112
  @sections.push( FXSection.new )
91
113
  @section = @sections.size - 1
92
114
  end
@@ -113,6 +135,48 @@ class FXMap < Map
113
135
  puts m
114
136
  end
115
137
 
138
+ #
139
+ # Determine whether a pathmap area from x,y to x+w,y+h is free
140
+ # of rooms
141
+ #
142
+ def _free_area?(x, y, w, h)
143
+ x.upto(x+w) { |xx|
144
+ y.upto(x+h) { |yy|
145
+ return false if @pmap[xx][yy].kind_of?(Room)
146
+ }
147
+ }
148
+ return true
149
+ end
150
+
151
+ #
152
+ # Given a list of rooms, find an area in the map where we could
153
+ # place them. If found, return x/y offset so rooms can be moved
154
+ # there. This is used for pasting rooms.
155
+ #
156
+ def find_empty_area(rooms)
157
+ return nil if rooms.empty?
158
+ minx = maxx = rooms[0].x
159
+ miny = maxy = rooms[0].y
160
+ rooms.each { |r|
161
+ minx = r.x if r.x < minx
162
+ maxx = r.x if r.x > maxx
163
+ miny = r.y if r.y < miny
164
+ maxy = r.y if r.y > maxy
165
+ }
166
+ w = maxx - minx
167
+ h = maxy - miny
168
+
169
+ # Find an area in pathmap that has w x h empty rooms
170
+ 0.upto(@width-1-w) { |x|
171
+ 0.upto(@height-1-h) { |y|
172
+ if _free_area?(x, y, w, h)
173
+ return [x - minx, y - miny]
174
+ end
175
+ }
176
+ }
177
+ return nil
178
+ end
179
+
116
180
  #
117
181
  # Reinitialize the pathmap to an empty matrix
118
182
  #
@@ -166,8 +230,6 @@ class FXMap < Map
166
230
  a = c.roomA
167
231
  b = c.roomB
168
232
 
169
- # First, check the neighboring starting/ending nodes in grid
170
- # are empty. If not, we need to abort and remove path from list.
171
233
  dirA = a.exits.index(c)
172
234
  raise "connection not found #{c} at #{a}" unless dirA
173
235
 
@@ -231,7 +293,7 @@ class FXMap < Map
231
293
  # We succeeded. Get the path
232
294
  c.failed = false
233
295
  c.gpts = aStar.path
234
- # Put path in pathmap so subsequent paths will avoid crossing it.
296
+ # Put path in pathmap so subsequent paths will try to avoid crossing it.
235
297
  c.gpts.each { |p| @pmap[p[0]][p[1]] = c }
236
298
 
237
299
  # Okay, we have a valid path.
@@ -289,20 +351,14 @@ class FXMap < Map
289
351
  end
290
352
 
291
353
  #
292
- # Function used to add a new room. x and y are absolute pixel positions
293
- # in canvas.
354
+ # Create a new room for the current section
294
355
  #
295
- def new_xy_room(x, y)
356
+ def new_room(x, y)
296
357
  @modified = true
297
- x = x / WW
298
- y = y / HH
299
358
  r = @sections[@section].new_room(x, y)
300
359
  @pmap[x][y] = r
301
360
 
302
- buf = FXMapperWindow::copy_buffer()
303
- r.copy(buf) if buf
304
361
  r.selected = true
305
-
306
362
 
307
363
  if @options['Edit on Creation']
308
364
  if not r.modal_properties(self)
@@ -311,10 +367,19 @@ class FXMap < Map
311
367
  return nil
312
368
  end
313
369
  end
314
-
315
370
  return r
316
371
  end
317
372
 
373
+ #
374
+ # Function used to add a new room. x and y are absolute pixel positions
375
+ # in canvas.
376
+ #
377
+ def new_xy_room(x, y)
378
+ x = x / WW
379
+ y = y / HH
380
+ return new_room(x, y)
381
+ end
382
+
318
383
 
319
384
  # Given a canvas (mouse) x/y position, return:
320
385
  #
@@ -360,14 +425,19 @@ class FXMap < Map
360
425
  next if not b # Complex connection in progress
361
426
 
362
427
  if c.gpts.size > 0
363
- [a, b].each { |r|
428
+ 2.times { |t|
429
+ if t == 0
430
+ r = a
431
+ dir = r.exits.index(c)
432
+ else
433
+ r = b
434
+ dir = r.exits.rindex(c)
435
+ end
364
436
  next if not r
365
- dir = r.exits.index(c)
366
437
  x1, y1 = r.corner(c, 1, dir)
367
438
  v = FXRoom::DIR_TO_VECTOR[dir]
368
439
  x2 = x1 + v[0] * WS
369
440
  y2 = y1 + v[1] * HS
370
-
371
441
  if x1 == x2
372
442
  x1 -= W / 2
373
443
  x2 += W / 2
@@ -376,6 +446,9 @@ class FXMap < Map
376
446
  y1 -= H / 2
377
447
  y2 += H / 2
378
448
  end
449
+ x1, x2 = x2, x1 if x2 < x1
450
+ y1, y2 = y2, y1 if y2 < y1
451
+
379
452
  if x >= x1 and x <= x2 and
380
453
  y >= y1 and y < y2
381
454
  return c
@@ -401,11 +474,7 @@ class FXMap < Map
401
474
  end
402
475
  }
403
476
 
404
- # Then, get "rooms" being connected to check if we get
405
- # a complex connection instead.
406
- roomA, roomB, a, b = quadrant_to_rooms( exitA, x, y )
407
- return roomA if roomA.kind_of?(Connection)
408
- return roomB if roomB.kind_of?(Connection)
477
+ return nil
409
478
  end
410
479
 
411
480
  return nil
@@ -547,7 +616,8 @@ class FXMap < Map
547
616
  roomB = to_room(x2, y2)
548
617
  # Oops, user tried to create rooms where we already
549
618
  # have a complex connection. Don't create anything, then.
550
- if roomA.kind_of?(Connection) or roomB.kind_of?(Connection)
619
+ if roomA.kind_of?(Connection) or
620
+ (roomB.kind_of?(Connection) and not @complexConnection)
551
621
  return [roomA, roomB, nil, nil]
552
622
  end
553
623
 
@@ -563,8 +633,13 @@ class FXMap < Map
563
633
  raise "not a connection"
564
634
  end
565
635
  roomA, roomB, a, b = quadrant_to_rooms( exitA, x, y )
566
- return unless a and roomA # User click outside map or not near room
567
-
636
+ unless a and roomA and roomA[exitA] == nil
637
+ return
638
+ end
639
+ _new_complex_connection(roomA, exitA)
640
+ end
641
+
642
+ def _new_complex_connection(roomA, exitA)
568
643
  if @complexConnection.kind_of?(TrueClass)
569
644
  @complexConnection = [roomA, exitA]
570
645
  c = new_connection( roomA, exitA, nil )
@@ -662,6 +737,9 @@ class FXMap < Map
662
737
  s.normalText = s.text = msg
663
738
  end
664
739
 
740
+ #
741
+ # Based on x,y coordinate, switch mouse icon shape
742
+ #
665
743
  def cursor_switch(x, y)
666
744
  if not @options['Use Room Cursor']
667
745
  @canvas.defaultCursor = @@cursor_arrow
@@ -726,42 +804,18 @@ class FXMap < Map
726
804
  # to cursor position
727
805
  #
728
806
  def mousewheel_cb(sender, sel, event)
729
- pos = @scrollwindow.position
730
- pos = [ pos[0] / @zoom, pos[1] / @zoom ]
731
- x = (event.last_x / @zoom).to_i
732
- y = (event.last_y / @zoom).to_i
807
+ # x = event.last_x / @zoom
808
+ # y = event.last_y / @zoom
733
809
  case event.code
734
810
  when -120
735
811
  zoom_out
736
- # pos[0] -= x / 2
737
- # pos[1] -= y / 2
738
- pos = [ pos[0] * @zoom, pos[1] * @zoom ]
739
- @scrollwindow.setPosition(pos[0], pos[1])
740
812
  when 120
741
813
  zoom_in
742
-
743
- #pos[0] = -x # * @zoom * 2
744
- #pos[1] = -y # * @zoom * 2
745
-
746
- # pos = [ pos[0], pos[1] ]
747
- # pos = [ pos[0] * @zoom, pos[1] * @zoom ]
748
- @scrollwindow.setPosition(pos[0], pos[1])
749
814
  end
750
- # x = (x * @zoom).to_i
751
- # y = (y * @zoom).to_i
752
- # if x > @canvas.width
753
- # x = @canvas.width
754
- # end
755
- # if y > @canvas.height
756
- # y = @canvas.height
757
- # end
758
-
759
- # pos = [ pos[0] - x, pos[1] - y ]
760
- # p "SET: #{pos.join(',')}"
761
-
762
- # # @scrollwindow.setPosition(pos[0], pos[1])
763
- # p @scrollwindow.position
764
- draw
815
+ # x *= @zoom
816
+ # y *= @zoom
817
+ # center_view_on_xy(x.to_i, y.to_i)
818
+ # draw
765
819
  end
766
820
 
767
821
  #
@@ -795,10 +849,28 @@ class FXMap < Map
795
849
  if r.x >= x1 and r.x <= x2 and
796
850
  r.y >= y1 and r.y <= y2
797
851
  r.selected = true
852
+ r.update_properties(self)
798
853
  else
799
854
  r.selected = false
800
855
  end
801
856
  }
857
+
858
+ @sections[@section].connections.each { |c|
859
+ next if not c.roomB
860
+ a = c.roomA
861
+ b = c.roomB
862
+
863
+ if (a.x >= x1 and a.x <= x2 and
864
+ a.y >= y1 and a.y <= y2) or
865
+ (b.x >= x1 and b.x <= x2 and
866
+ b.y >= y1 and b.y <= y2)
867
+ c.selected = true
868
+ c.update_properties(self)
869
+ else
870
+ c.selected = false
871
+ end
872
+ }
873
+
802
874
  draw
803
875
  dc = FXDCWindow.new(@canvas)
804
876
  dc.drawRectangle(x, y, w * @zoom, h * @zoom)
@@ -842,6 +914,52 @@ class FXMap < Map
842
914
  end
843
915
  end
844
916
 
917
+ #
918
+ # Given a room, center scrollwindow so room is visible
919
+ #
920
+ def center_view_on_room(r)
921
+ xx = (r.xx + W / 2) * @zoom
922
+ yy = (r.yy + H / 2) * @zoom
923
+ center_view_on_xy(xx, yy)
924
+ end
925
+
926
+ #
927
+ # Given an x and y coordinate for the canvas, center on it
928
+ #
929
+ def center_view_on_xy(xx, yy)
930
+ cw = @scrollwindow.getContentWidth
931
+ ch = @scrollwindow.getContentHeight
932
+ w = @scrollwindow.getViewportWidth
933
+ h = @scrollwindow.getViewportHeight
934
+
935
+ xx -= w / 2
936
+ yy -= h / 2
937
+ maxx = cw - w / 2
938
+ maxy = ch - h / 2
939
+ if xx > maxx
940
+ xx = maxx
941
+ elsif xx < 0
942
+ xx = 0
943
+ end
944
+ if yy > maxy
945
+ yy = maxy
946
+ elsif yy < 0
947
+ yy = 0
948
+ end
949
+
950
+ @scrollwindow.setPosition( -xx, -yy )
951
+ end
952
+
953
+ #
954
+ # Return current selection as an array of rooms and an array of
955
+ # connections
956
+ #
957
+ def get_selection
958
+ rooms = @sections[@section].rooms.find_all { |r| r.selected }
959
+ conns = @sections[@section].connections.find_all { |r| r.selected }
960
+ return rooms, conns
961
+ end
962
+
845
963
  #
846
964
  # Clear rooms/connections selected
847
965
  #
@@ -850,6 +968,66 @@ class FXMap < Map
850
968
  @sections[@section].connections.each { |r| r.selected = false }
851
969
  end
852
970
 
971
+ #
972
+ # Add a proper link submenu option for an exit
973
+ #
974
+ def rmb_link_menu(submenu, c, room, idx, old_idx)
975
+ return if room[idx] == c
976
+ dir = Room::DIRECTIONS[idx]
977
+ dir = dir.upcase
978
+ if room[idx]
979
+ cmd = FXMenuCommand.new(submenu, "Switch with link in #{dir} Exit")
980
+ cmd.connect(SEL_COMMAND) {
981
+ c2 = room[idx]
982
+ room[old_idx] = c2
983
+ room[idx] = c
984
+ create_pathmap
985
+ draw
986
+ }
987
+ else
988
+ cmd = FXMenuCommand.new(submenu, "Move link to #{dir} Exit")
989
+ cmd.connect(SEL_COMMAND) {
990
+ room[old_idx] = nil
991
+ room[idx] = c
992
+ create_pathmap
993
+ draw
994
+ }
995
+ end
996
+ end
997
+
998
+ #
999
+ # Handle right mouse button click
1000
+ #
1001
+ def rmb_click_cb(sender, sel, event)
1002
+ rooms, links = get_selection
1003
+
1004
+ menu = nil
1005
+ if not links.empty? and links.size == 1
1006
+ c = links[0]
1007
+ a = c.roomA
1008
+ b = c.roomB
1009
+ menu = FXMenuPane.new(@window)
1010
+ submenu = FXMenuPane.new(@window)
1011
+ old_idx = a.exits.index(c)
1012
+ 0.upto(7) { |idx|
1013
+ rmb_link_menu( submenu, c, a, idx, old_idx )
1014
+ }
1015
+ FXMenuCascade.new(menu, a.name, nil, submenu)
1016
+ submenu = FXMenuPane.new(@window)
1017
+ old_idx = b.exits.rindex(c)
1018
+ 0.upto(7) { |idx|
1019
+ rmb_link_menu( submenu, c, b, idx, old_idx )
1020
+ }
1021
+ FXMenuCascade.new(menu, b.name, nil, submenu)
1022
+ end
1023
+ if menu
1024
+ menu.create
1025
+ menu.popup(nil, event.root_x, event.root_y)
1026
+ @window.getApp.runModalWhileShown(menu)
1027
+ end
1028
+ end
1029
+
1030
+
853
1031
  #
854
1032
  # Handle left mouse button click
855
1033
  #
@@ -911,9 +1089,11 @@ class FXMap < Map
911
1089
  if not roomA
912
1090
  new_xy_connection( x, y )
913
1091
  else
914
- @complexConnection = [roomA, exitA]
915
- new_connection( roomA, exitA, nil )
916
- new_complex_connection( x, y )
1092
+ if a and roomA
1093
+ @complexConnection = [roomA, exitA]
1094
+ new_connection( roomA, exitA, nil )
1095
+ _new_complex_connection( roomA, exitA )
1096
+ end
917
1097
  end
918
1098
  else
919
1099
  new_xy_connection( x, y )
@@ -932,6 +1112,7 @@ class FXMap < Map
932
1112
  clear_selection
933
1113
  end
934
1114
  # Select the stuff
1115
+ selection.update_properties(self)
935
1116
  selection.selected = true
936
1117
  end
937
1118
  end
@@ -1057,6 +1238,7 @@ class FXMap < Map
1057
1238
  @canvas.connect(SEL_MOTION, method(:motion_cb))
1058
1239
  @canvas.connect(SEL_MIDDLEBUTTONPRESS, method(:mmb_click_cb))
1059
1240
  @canvas.connect(SEL_MIDDLEBUTTONRELEASE, method(:mmb_release_cb))
1241
+ @canvas.connect(SEL_RIGHTBUTTONPRESS, method(:rmb_click_cb))
1060
1242
  @canvas.connect(SEL_KEYPRESS, method(:keypress_cb))
1061
1243
  end
1062
1244
 
@@ -1167,6 +1349,9 @@ class FXMap < Map
1167
1349
  @modified = true
1168
1350
  end
1169
1351
 
1352
+ #
1353
+ # Give user some warning if he tries to modify a read-only mode.
1354
+ #
1170
1355
  def navigation_warning
1171
1356
  w = FXWarningBox.new(@window, "Map is in Read Only Mode. Go to Map Information to change this.")
1172
1357
  w.execute
@@ -1446,6 +1631,32 @@ class FXMap < Map
1446
1631
  # Print map
1447
1632
  #
1448
1633
  def print(printer)
1634
+ # dc = FXDCPrint.new(@window.getApp)
1635
+ require 'IFMapper/FXDCPostscript'
1636
+ oldzoom = @zoom
1637
+ oldsection = @section
1638
+ begin
1639
+ dc = FXDCPostscript.new(@window.getApp)
1640
+ xmax = @width * WW
1641
+ ymax = @height * HH
1642
+ @zoom = 1.0
1643
+ dc.setContentRange(0, 0, xmax, ymax)
1644
+ dc.beginPrint(printer) {
1645
+ 0.upto(@sections.size-1) { |p|
1646
+ self.section = p
1647
+ clear_selection
1648
+ dc.beginPage(p+1) {
1649
+ dc.lineCap = CAP_ROUND
1650
+ draw_connections(dc)
1651
+ draw_rooms(dc)
1652
+ }
1653
+ }
1654
+ }
1655
+ rescue => e
1656
+ status "#{e}"
1657
+ end
1658
+ self.section = oldsection
1659
+ @zoom = oldzoom
1449
1660
  end
1450
1661
 
1451
1662
  #
@@ -1459,7 +1670,7 @@ class FXMap < Map
1459
1670
  dc = FXDCWindow.new(@image)
1460
1671
  dc.setClipRectangle( -pos[0]-5, -pos[1]-5, w, h)
1461
1672
  dc.font = @font
1462
- # dc.lineCap = CAP_ROUND
1673
+ #dc.lineCap = CAP_ROUND
1463
1674
  draw_background(dc, event)
1464
1675
  draw_grid(dc, event) if @options['Grid Boxes']
1465
1676
  if @options['Grid Straight Connections']