ifmapper 1.0.0 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. data/HISTORY.txt +648 -627
  2. data/IFMapper.gemspec +29 -28
  3. data/IFMapper.rbw +31 -31
  4. data/TODO.txt +8 -7
  5. data/bin/IFMapper +31 -31
  6. data/docs/en/index.html +0 -0
  7. data/docs/en/start.html +3 -2
  8. data/docs/en/start.html~ +516 -0
  9. data/docs/es/index.html +0 -0
  10. data/docs/es/start.html +13 -14
  11. data/docs/es/start.html~ +1280 -0
  12. data/docs/images/IFMapper_main.gif +0 -0
  13. data/docs/images/automap.gif +0 -0
  14. data/docs/images/complex_connection.gif +0 -0
  15. data/docs/images/connection.gif +0 -0
  16. data/docs/images/connection_menu.gif +0 -0
  17. data/docs/images/room_description.gif +0 -0
  18. data/docs/images/room_small.gif +0 -0
  19. data/icons/copy.png +0 -0
  20. data/icons/cut.png +0 -0
  21. data/icons/filenew.png +0 -0
  22. data/icons/fileopen.png +0 -0
  23. data/icons/filesave.png +0 -0
  24. data/icons/filesaveas.png +0 -0
  25. data/icons/help.png +0 -0
  26. data/icons/kill.png +0 -0
  27. data/icons/nextpage.png +0 -0
  28. data/icons/paste.png +0 -0
  29. data/icons/prevpage.png +0 -0
  30. data/icons/printicon.png +0 -0
  31. data/icons/redo.png +0 -0
  32. data/icons/room_e.gif +0 -0
  33. data/icons/room_e.xpm +0 -0
  34. data/icons/room_n.gif +0 -0
  35. data/icons/room_n.xpm +0 -0
  36. data/icons/room_ne.gif +0 -0
  37. data/icons/room_ne.xpm +0 -0
  38. data/icons/room_nw.gif +0 -0
  39. data/icons/room_nw.xpm +0 -0
  40. data/icons/room_s.gif +0 -0
  41. data/icons/room_s.xpm +0 -0
  42. data/icons/room_se.gif +0 -0
  43. data/icons/room_se.xpm +0 -0
  44. data/icons/room_sw.gif +0 -0
  45. data/icons/room_sw.xpm +0 -0
  46. data/icons/room_w.gif +0 -0
  47. data/icons/room_w.xpm +0 -0
  48. data/icons/saveas.png +0 -0
  49. data/icons/undo.png +0 -0
  50. data/icons/winapp.png +0 -0
  51. data/icons/zoom.png +0 -0
  52. data/lib/IFMapper/AStar.rb +250 -250
  53. data/lib/IFMapper/Connection.rb +202 -202
  54. data/lib/IFMapper/FXAboutDialogBox.rb +32 -32
  55. data/lib/IFMapper/FXConnection.rb +364 -364
  56. data/lib/IFMapper/FXConnectionDialogBox.rb +124 -124
  57. data/lib/IFMapper/FXDCPostscript.rb +404 -404
  58. data/lib/IFMapper/FXDCPrint.rb +15 -15
  59. data/lib/IFMapper/FXItemList.rb +108 -0
  60. data/lib/IFMapper/FXMap.rb +2147 -2116
  61. data/lib/IFMapper/FXMapColorBox.rb +88 -88
  62. data/lib/IFMapper/FXMapDialogBox.rb +127 -127
  63. data/lib/IFMapper/FXMapFileDialog.rb +34 -34
  64. data/lib/IFMapper/FXMapperSettings.rb +206 -205
  65. data/lib/IFMapper/FXMapperWindow.rb +1592 -1571
  66. data/lib/IFMapper/FXPDFMapExporterOptionsDialogBox.rb +46 -0
  67. data/lib/IFMapper/FXRoom.rb +263 -263
  68. data/lib/IFMapper/FXRoomDialogBox.rb +159 -159
  69. data/lib/IFMapper/FXRoomList.rb +95 -95
  70. data/lib/IFMapper/FXSearchDialogBox.rb +51 -51
  71. data/lib/IFMapper/FXSection.rb +33 -33
  72. data/lib/IFMapper/FXSectionDialogBox.rb +38 -38
  73. data/lib/IFMapper/FXSpline.rb +52 -52
  74. data/lib/IFMapper/FXWarningBox.rb +51 -50
  75. data/lib/IFMapper/GUEReader.rb +445 -445
  76. data/lib/IFMapper/IFMReader.rb +584 -584
  77. data/lib/IFMapper/IFMWriter.rb +245 -227
  78. data/lib/IFMapper/Inform7Writer.rb +579 -573
  79. data/lib/IFMapper/InformReader.rb +478 -478
  80. data/lib/IFMapper/InformWriter.rb +364 -359
  81. data/lib/IFMapper/Map.rb +202 -200
  82. data/lib/IFMapper/MapPrinting.rb +162 -162
  83. data/lib/IFMapper/MapReader.rb +900 -900
  84. data/lib/IFMapper/PDFMapExporter.rb +526 -483
  85. data/lib/IFMapper/Room.rb +153 -151
  86. data/lib/IFMapper/Section.rb +234 -234
  87. data/lib/IFMapper/TADSReader.rb +474 -471
  88. data/lib/IFMapper/TADSWriter.rb +375 -370
  89. data/lib/IFMapper/TranscriptDialogBox.rb +0 -0
  90. data/lib/IFMapper/TranscriptReader.rb +1361 -1359
  91. data/lib/IFMapper/locales/en/Messages.rb +446 -435
  92. data/lib/IFMapper/locales/es/Messages.rb +451 -440
  93. data/lib/IFMapper/locales/es/Messages_iso-8859-1.rb +455 -440
  94. data/lib/IFMapper/locales/es/runme.sh +3 -3
  95. data/maps/A New Life.map b/data/maps/A New → Life.map +0 -0
  96. data/maps/AMFV.map +0 -0
  97. data/maps/AllRoads.map +0 -0
  98. data/maps/Aotearoa.map +0 -0
  99. data/maps/Bronze.map +0 -0
  100. data/maps/Bureaucracy.ifm +0 -0
  101. data/maps/Bureaucracy.map +0 -0
  102. data/maps/CityOfSecrets.map +0 -0
  103. data/maps/DDIV.map +0 -0
  104. data/maps/Following_A_Star.map +0 -0
  105. data/maps/Heated.map +0 -0
  106. data/maps/Heroine.map +0 -0
  107. data/maps/History Repeating.map b/data/maps/History → Repeating.map +0 -0
  108. data/maps/Hollywood_Hijinx.ifm +0 -0
  109. data/maps/Janitor.map +0 -0
  110. data/maps/Jigsaw.ifm +0 -0
  111. data/maps/Jigsaw.map +0 -0
  112. data/maps/LGOP.ifm +0 -0
  113. data/maps/Mercy.ifm +0 -0
  114. data/maps/Ninjas_Fate.map +0 -0
  115. data/maps/Pen_and_Paint.map +0 -0
  116. data/maps/Planetfall.ifm +0 -0
  117. data/maps/Planetfall.map +0 -0
  118. data/maps/Plundered_Hearts.ifm +0 -0
  119. data/maps/QuietEvening.map +0 -0
  120. data/maps/Ralph.ifm +0 -0
  121. data/maps/Reliques_of_Tolti_Alph.map +0 -0
  122. data/maps/Revolution.map +0 -0
  123. data/maps/Robots_of_Dawn.ifm +0 -0
  124. data/maps/SavoirFare.map +0 -0
  125. data/maps/Seastalker.ifm +0 -0
  126. data/maps/Seastalker.map +0 -0
  127. data/maps/Sherlock.ifm +0 -0
  128. data/maps/SoFar.ifm +0 -0
  129. data/maps/Starcross.ifm +0 -0
  130. data/maps/Suspended.ifm +0 -0
  131. data/maps/Tangle.map +0 -0
  132. data/maps/The_Lost_Sheep.map +0 -0
  133. data/maps/Unforgotten.map +0 -0
  134. data/maps/Warbler's Nest.map +0 -0
  135. data/maps/Warbler's_Nest.map +0 -0
  136. data/maps/Westminster_Abbey.map +0 -0
  137. data/maps/WinterWonderland.map +0 -0
  138. data/maps/Wishbringer.ifm +0 -0
  139. data/maps/Wishbringer2.ifm +0 -0
  140. data/maps/Zork1.ifm +0 -0
  141. data/maps/Zork2.ifm +0 -0
  142. data/maps/Zork3.ifm +0 -0
  143. data/maps/Zork_Zero.ifm +0 -0
  144. data/maps/anchor.ifm +0 -0
  145. data/maps/anchor.map +0 -0
  146. data/maps/atrox.ifm +0 -0
  147. data/maps/awaken.ifm +0 -0
  148. data/maps/babel.ifm +0 -0
  149. data/maps/balances.map +0 -0
  150. data/maps/ballerina.map +0 -0
  151. data/maps/bear.map +0 -0
  152. data/maps/bluechairs.map +0 -0
  153. data/maps/break_in.map +0 -0
  154. data/maps/bse.ifm +0 -0
  155. data/maps/building.map +0 -0
  156. data/maps/change.ifm +0 -0
  157. data/maps/christminster.map +0 -0
  158. data/maps/curses.ifm +0 -0
  159. data/maps/curves.ifm +0 -0
  160. data/maps/deadline.map +0 -0
  161. data/maps/delusions.map +0 -0
  162. data/maps/devours.map +0 -0
  163. data/maps/distress.map +0 -0
  164. data/maps/djinni.map +0 -0
  165. data/maps/dreamhold.map +0 -0
  166. data/maps/drift3.map +0 -0
  167. data/maps/eas.map +0 -0
  168. data/maps/eas2.map +0 -0
  169. data/maps/eas3.map +0 -0
  170. data/maps/edifice.ifm +0 -0
  171. data/maps/fallacy.map +0 -0
  172. data/maps/frozen.ifm +0 -0
  173. data/maps/gamlet.map +0 -0
  174. data/maps/glow.ifm +0 -0
  175. data/maps/guilty_bastards.map +0 -0
  176. data/maps/heist.map +0 -0
  177. data/maps/heroes.map +0 -0
  178. data/maps/inhumane.map +0 -0
  179. data/maps/kaged.map +0 -0
  180. data/maps/library.ifm +0 -0
  181. data/maps/lurkinghorror.map +0 -0
  182. data/maps/metamorphoses.map +0 -0
  183. data/maps/mindelec.ifm +0 -0
  184. data/maps/minster.ifm +0 -0
  185. data/maps/mite.map +0 -0
  186. data/maps/moonmist.map +0 -0
  187. data/maps/muldoon_legacy.map +0 -0
  188. data/maps/muse.ifm +0 -0
  189. data/maps/paperchase.ifm +0 -0
  190. data/maps/party.map +0 -0
  191. data/maps/pawn.map +0 -0
  192. data/maps/photograph.map +0 -0
  193. data/maps/pkgirl.map +0 -0
  194. data/maps/pytho.map +0 -0
  195. data/maps/risorgimento.map +0 -0
  196. data/maps/sherbet.map +0 -0
  197. data/maps/simple.map +0 -0
  198. data/maps/slouch.map +0 -0
  199. data/maps/space_st.ifm +0 -0
  200. data/maps/splashdown.map +0 -0
  201. data/maps/spring.map +0 -0
  202. data/maps/squarecircle.map +0 -0
  203. data/maps/stationfall.ifm +0 -0
  204. data/maps/theatre.ifm +0 -0
  205. data/maps/toonesia.ifm +0 -0
  206. data/maps/tortoise.ifm +0 -0
  207. data/maps/trinity.map +0 -0
  208. data/maps/vespers.map +0 -0
  209. data/maps/vgame.ifm +0 -0
  210. data/maps/wasp.map +0 -0
  211. data/maps/weather.ifm +0 -0
  212. data/maps/windhall.ifm +0 -0
  213. data/maps/worlds.map +0 -0
  214. data/maps/xtcontest.map +0 -0
  215. data/maps/zdungeon.map +0 -0
  216. data/maps/zebulon.ifm +0 -0
  217. data/maps/zerosum.map +0 -0
  218. metadata +226 -183
@@ -1,205 +1,206 @@
1
-
2
- begin
3
- require 'iconv'
4
- rescue LoadError
5
- $stderr.puts 'Iconv could not be loaded. Languages other than English will have problems'
6
- class Iconv
7
- def initialize(to, from)
8
- end
9
-
10
- def iconv(a)
11
- a
12
- end
13
- end
14
- end
15
-
16
-
17
- #
18
- # This class contains the applicatio and map's settings
19
- #
20
- class FXMapperSettings < Hash
21
-
22
- class UnknownParameter < StandardError; end;
23
-
24
- #
25
- # Return the home location
26
- #
27
- # Result: home location for user
28
- #
29
- def home
30
- if ENV['HOME']
31
- homedir = File.expand_path('~')
32
- # Ahh... you have to love windows...
33
- elsif ENV['USERPROFILE']
34
- homedir = ENV['USERPROFILE']
35
- elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
36
- homedir = ENV['HOMEDRIVE'] + ENV['HOMEPATH']
37
- else
38
- homedir = '.'
39
- end
40
- return homedir
41
- end
42
-
43
-
44
- #
45
- # Write out the preferences to disk.
46
- #
47
- # Result: none
48
- #
49
- def write
50
- begin
51
- file = home + '/.ifmapper'
52
- f = File.open(file, 'w')
53
- f.puts YAML.dump(self)
54
- f.close
55
- rescue => e
56
- $stderr.puts "Preferences not saved:"
57
- $stderr.puts e
58
- end
59
- end
60
-
61
-
62
- if RUBY_PLATFORM =~ /mswin/
63
- require 'Win32API'
64
- LOCALE_USER_DEFAULT = 0x400
65
- LOCALE_SLANGUAGE = 0x1001
66
-
67
- FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
68
- FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
69
- FormatMessage = Win32API.new("kernel32","FormatMessage","LPLLPLP","L")
70
- GetLastError = Win32API.new("kernel32","GetLastError",[],"L")
71
- GetLocaleInfo = Win32API.new('Kernel32.dll', 'GetLocaleInfo',
72
- %w{l l p i}, 'i')
73
-
74
- LANGUAGES = {
75
- /English/ => 'en',
76
- /Spanish/ => 'es',
77
- # todo1
78
- /German/ => 'de',
79
- /Italian/ => 'it',
80
- /French/ => 'fr',
81
- /Japanese/ => 'ja',
82
- /Chinese/ => 'ch',
83
- /Korean/ => 'ko',
84
- /Arabic/ => 'ar',
85
- /Hebrew/ => 'he',
86
- }
87
- end
88
-
89
-
90
- #
91
- # Restore user preferences
92
- #
93
- # Result:
94
- #
95
- def initialize
96
- has_yaml = true
97
- begin
98
- require 'yaml'
99
- f = home + '/.ifmapper'
100
- self.replace( YAML.load_file(f) )
101
- rescue LoadError
102
- has_yaml = false
103
- rescue
104
- end
105
-
106
- if RUBY_PLATFORM =~ /mswin/
107
- lcid = LOCALE_USER_DEFAULT
108
- lctype = LOCALE_SLANGUAGE
109
- slanguage = '\0' * 256
110
- len = 256
111
- ret = GetLocaleInfo.call lcid, lctype, slanguage, len
112
- if ret == 0
113
- error_code = GetLastError.call
114
- msg = " " * 255
115
- FormatMessage.call(
116
- FORMAT_MESSAGE_FROM_SYSTEM +
117
- FORMAT_MESSAGE_ARGUMENT_ARRAY,
118
- '',
119
- error_code,
120
- 0,
121
- msg,
122
- 255,
123
- ''
124
- )
125
- msg.gsub!(/\000/, '')
126
- msg.strip!
127
- $stderr.puts msg
128
- end
129
- language = 'en'
130
- LANGUAGES.each { |re, locale|
131
- if slanguage =~ re
132
- language = locale
133
- break
134
- end
135
- }
136
- else
137
- locale = ENV['LC_ALL'] || ENV['LC_CTYPE'] || 'en_US'
138
- language = locale[0,2]
139
- end
140
-
141
- while ARGV.size > 0
142
- param = ARGV.shift
143
- case param
144
- when /^-l(anguage)?$/
145
- language = ARGV.shift
146
- language = language[0,2].downcase
147
- self['Language'] = language
148
- else
149
- $stderr.puts "Unknown parameter '#{param}'."
150
- exit(1)
151
- end
152
- end
153
-
154
- defaults = {
155
- # Language
156
- 'Language' => language,
157
-
158
- # Colors
159
- 'BG Color' => 'dark grey',
160
- 'Arrow Color' => 'black',
161
- 'Box BG Color' => 'white',
162
- 'Box Darkness Color' => 'grey',
163
- 'Box Border Color' => 'black',
164
- 'Box Number Color' => 'grey',
165
-
166
- # Fonts
167
- 'Font Text' => 'Times',
168
- 'Font Objects' => 'Times',
169
-
170
- # Creation options
171
- 'Create on Connection' => true,
172
- 'Edit on Creation' => false,
173
- 'Automatic Connection' => true,
174
-
175
-
176
- # Display options
177
- 'Use Room Cursor' => false,
178
- 'Paths as Curves' => true,
179
-
180
- # Location options
181
- 'Location Tasks' => true,
182
- 'Location Description' => false,
183
- 'Location Numbers' => true,
184
-
185
- # Grid options
186
- 'Grid Boxes' => true,
187
- 'Grid Straight Connections' => true,
188
- 'Grid Diagonal Connections' => false,
189
-
190
- }
191
-
192
- self.replace( defaults.merge(self) )
193
- language = self['Language']
194
-
195
- begin
196
- require "IFMapper/locales/#{language}/Messages.rb"
197
- rescue LoadError => e
198
- puts "Language '#{language}' was not found."
199
- end
200
-
201
- unless has_yaml
202
- $stderr.puts ERR_NO_YAML
203
- end
204
- end
205
- end
1
+
2
+ begin
3
+ require 'iconv'
4
+ rescue LoadError
5
+ $stderr.puts 'Iconv could not be loaded. Languages other than English will have problems'
6
+ class Iconv
7
+ def initialize(to, from)
8
+ end
9
+
10
+ def iconv(a)
11
+ a
12
+ end
13
+ end
14
+ end
15
+
16
+
17
+ #
18
+ # This class contains the applicatio and map's settings
19
+ #
20
+ class FXMapperSettings < Hash
21
+
22
+ class UnknownParameter < StandardError; end;
23
+
24
+ #
25
+ # Return the home location
26
+ #
27
+ # Result: home location for user
28
+ #
29
+ def home
30
+ if ENV['HOME']
31
+ homedir = File.expand_path('~')
32
+ # Ahh... you have to love windows...
33
+ elsif ENV['USERPROFILE']
34
+ homedir = ENV['USERPROFILE']
35
+ elsif ENV['HOMEDRIVE'] and ENV['HOMEPATH']
36
+ homedir = ENV['HOMEDRIVE'] + ENV['HOMEPATH']
37
+ else
38
+ homedir = '.'
39
+ end
40
+ return homedir
41
+ end
42
+
43
+
44
+ #
45
+ # Write out the preferences to disk.
46
+ #
47
+ # Result: none
48
+ #
49
+ def write
50
+ begin
51
+ file = home + '/.ifmapper'
52
+ f = File.open(file, 'w')
53
+ f.puts YAML.dump(self)
54
+ f.close
55
+ rescue => e
56
+ $stderr.puts "Preferences not saved:"
57
+ $stderr.puts e
58
+ end
59
+ end
60
+
61
+
62
+ if RUBY_PLATFORM =~ /mswin/
63
+ require 'Win32API'
64
+ LOCALE_USER_DEFAULT = 0x400
65
+ LOCALE_SLANGUAGE = 0x1001
66
+
67
+ FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
68
+ FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
69
+ FormatMessage = Win32API.new("kernel32","FormatMessage","LPLLPLP","L")
70
+ GetLastError = Win32API.new("kernel32","GetLastError",[],"L")
71
+ GetLocaleInfo = Win32API.new('Kernel32.dll', 'GetLocaleInfo',
72
+ %w{l l p i}, 'i')
73
+
74
+ LANGUAGES = {
75
+ /English/ => 'en',
76
+ /Spanish/ => 'es',
77
+ # todo1
78
+ /German/ => 'de',
79
+ /Italian/ => 'it',
80
+ /French/ => 'fr',
81
+ /Japanese/ => 'ja',
82
+ /Chinese/ => 'ch',
83
+ /Korean/ => 'ko',
84
+ /Arabic/ => 'ar',
85
+ /Hebrew/ => 'he',
86
+ }
87
+ end
88
+
89
+
90
+ #
91
+ # Restore user preferences
92
+ #
93
+ # Result:
94
+ #
95
+ def initialize
96
+ has_yaml = true
97
+ begin
98
+ require 'yaml'
99
+ f = home + '/.ifmapper'
100
+ self.replace( YAML.load_file(f) )
101
+ rescue LoadError
102
+ has_yaml = false
103
+ rescue
104
+ end
105
+
106
+ if RUBY_PLATFORM =~ /mswin/
107
+ lcid = LOCALE_USER_DEFAULT
108
+ lctype = LOCALE_SLANGUAGE
109
+ slanguage = '\0' * 256
110
+ len = 256
111
+ ret = GetLocaleInfo.call lcid, lctype, slanguage, len
112
+ if ret == 0
113
+ error_code = GetLastError.call
114
+ msg = " " * 255
115
+ FormatMessage.call(
116
+ FORMAT_MESSAGE_FROM_SYSTEM +
117
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
118
+ '',
119
+ error_code,
120
+ 0,
121
+ msg,
122
+ 255,
123
+ ''
124
+ )
125
+ msg.gsub!(/\000/, '')
126
+ msg.strip!
127
+ $stderr.puts msg
128
+ end
129
+ language = 'en'
130
+ LANGUAGES.each { |re, locale|
131
+ if slanguage =~ re
132
+ language = locale
133
+ break
134
+ end
135
+ }
136
+ else
137
+ locale = ENV['LC_ALL'] || ENV['LC_CTYPE'] || 'en_US'
138
+ language = locale[0,2]
139
+ end
140
+
141
+ while ARGV.size > 0
142
+ param = ARGV.shift
143
+ case param
144
+ when /^-l(anguage)?$/
145
+ language = ARGV.shift
146
+ language = language[0,2].downcase
147
+ self['Language'] = language
148
+ else
149
+ $stderr.puts "Unknown parameter '#{param}'."
150
+ exit(1)
151
+ end
152
+ end
153
+
154
+ defaults = {
155
+ # Language
156
+ 'Language' => language,
157
+
158
+ # Colors
159
+ 'BG Color' => 'dark grey',
160
+ 'Arrow Color' => 'black',
161
+ 'Box BG Color' => 'white',
162
+ 'Box Darkness Color' => 'grey',
163
+ 'Box Border Color' => 'black',
164
+ 'Box Number Color' => 'grey',
165
+
166
+ # Fonts
167
+ 'Font Text' => 'Times',
168
+ 'Font Objects' => 'Times',
169
+
170
+ # Creation options
171
+ 'Create on Connection' => true,
172
+ 'Edit on Creation' => false,
173
+ 'Automatic Connection' => true,
174
+
175
+
176
+ # Display options
177
+ 'Use Room Cursor' => false,
178
+ 'Paths as Curves' => true,
179
+
180
+ # Location options
181
+ 'Location Tasks' => true,
182
+ 'Location Description' => false,
183
+ 'Location Numbers' => true,
184
+
185
+ # Grid options
186
+ 'Grid Boxes' => true,
187
+ 'Grid Straight Connections' => true,
188
+ 'Grid Diagonal Connections' => false,
189
+
190
+ }
191
+
192
+ self.replace( defaults.merge(self) )
193
+ language = self['Language']
194
+
195
+ begin
196
+ require "IFMapper/locales/#{language}/Messages.rb"
197
+ rescue LoadError => e
198
+ $stderr.puts "Language '#{language}' was not found. Using English."
199
+ require "IFMapper/locales/en/Messages.rb"
200
+ end
201
+
202
+ unless has_yaml
203
+ $stderr.puts ERR_NO_YAML
204
+ end
205
+ end
206
+ end
@@ -1,1571 +1,1592 @@
1
-
2
-
3
- begin
4
- $rubygems = false
5
- require 'rubygems'
6
- $rubygems = true
7
- rescue LoadError
8
- end
9
-
10
- def no_fox
11
- $stderr.puts ERR_NO_FOX
12
- if $rubygems
13
- $stderr.puts ERR_HAS_GEMS
14
- end
15
- exit(1)
16
- end
17
-
18
- def get_fox
19
- ##### ARRRGH!!!! Why does Lyle keep changing the fxruby name on each
20
- ##### release!
21
- foxes = [ 'fox16', 'fox14', 'fox12', 'fox' ]
22
- foxes.each { |fox|
23
- begin
24
- require "#{fox}"
25
- require "#{fox}/colors"
26
- break
27
- rescue LoadError
28
- no_fox if fox == foxes[-1]
29
- end
30
- }
31
-
32
- # verify fxruby version
33
- ver, rev, = Fox::fxrubyversion().split('.')
34
- no_fox if ver.to_i < 1 or rev.to_i < 2
35
- end
36
-
37
-
38
- get_fox
39
- include Fox
40
-
41
- require 'IFMapper/FXMap'
42
- require 'IFMapper/FXMapperSettings'
43
- require 'IFMapper/FXWarningBox'
44
-
45
-
46
- class FXMapperWindow < FXMainWindow
47
-
48
- PROGRAM_NAME = "Interactive Fiction Mapper"
49
- VERSION = '1.0.0'
50
- AUTHOR = "Gonzalo Garramuño"
51
-
52
- @@copy_buffer = nil
53
- @@default_options = FXMapperSettings.new
54
-
55
- LANGUAGES = {
56
- 'English' => 'en',
57
- 'Español' => 'es',
58
- # todo1
59
- 'Deutsch' => 'de',
60
- 'Italiano' => 'it',
61
- 'Fran�ais' => 'fr',
62
- # todo2
63
- 'Japanese' => 'ja',
64
- 'Chinese' => 'ch',
65
- 'Korean' => 'ko',
66
- 'Arabic' => 'ar',
67
- }
68
-
69
- def open_map(file)
70
- tmp = nil
71
- begin
72
- f = File.open(file, 'rb')
73
- tmp = Marshal.load(f)
74
- f.close
75
- tmp.filename = file
76
- rescue => e
77
- tmp = e
78
- end
79
- return tmp
80
- end
81
-
82
- def open_ifm(file, map)
83
- require 'IFMapper/IFMReader'
84
- begin
85
- IFMReader.new(file, map)
86
- rescue => e
87
- return "#{e} #{e.backtrace}"
88
- end
89
- return map
90
- end
91
-
92
- def open_tads(file, map)
93
- require 'IFMapper/TADSReader'
94
- begin
95
- TADSReader.new(file, map)
96
- rescue => e
97
- return "#{e}"
98
- end
99
- return map
100
- end
101
-
102
- def open_inform(file, map)
103
- require 'IFMapper/InformReader'
104
- begin
105
- InformReader.new(file, map)
106
- rescue => e
107
- return "#{e}"
108
- end
109
- return map
110
- end
111
-
112
- def open_guemap(file, map)
113
- require 'IFMapper/GUEReader'
114
- begin
115
- GUEReader.new(file, map)
116
- rescue => e
117
- return "#{e}"
118
- end
119
- return map
120
- end
121
-
122
- #
123
- # Start automapping from a transcript
124
- #
125
- def start_automap_cb(sender, sel, ptr)
126
- map = current_map
127
- return if not map
128
- map.start_automap
129
- end
130
-
131
- #
132
- # Properties of the automapper callback
133
- #
134
- def automap_properties_cb(sender, sel, ptr)
135
- map = current_map
136
- return if not map or not map.automap
137
- map.automap.properties(true)
138
- end
139
-
140
- #
141
- # Stop automapping from a transcript
142
- #
143
- def stop_automap_cb(sender, sel, ptr)
144
- map = current_map
145
- return if not map
146
- map.stop_automap
147
- end
148
-
149
-
150
- #
151
- # Callback to Open File
152
- #
153
- def open_cb(sender, sel, ptr)
154
- require 'IFMapper/FXMapFileDialog'
155
- file = FXMapFileDialog.new(self, MSG_LOAD_MAP).filename
156
- return if file == ''
157
-
158
- # First, make sure we don't have it loaded already...
159
- @maps.each { |m|
160
- if m.filename == file
161
- @mdiclient.setActiveChild(m.window)
162
- return
163
- end
164
- }
165
-
166
- # Then, check if we have a single and empty map.
167
- # If so, we can just use that one to load the file in.
168
- # If not, we need to create a new map
169
- make_new_map = false
170
- if @maps.size == 1
171
- @maps[0].sections.each { |p|
172
- if p.rooms.size != 0
173
- make_new_map = true
174
- break
175
- end
176
- }
177
- else
178
- make_new_map = true
179
- end
180
-
181
- if make_new_map
182
- map = new_map
183
- else
184
- map = @maps[0]
185
- end
186
- status "#{MSG_LOADING} '#{file}'..."
187
-
188
- tmp = nil
189
- if file =~ /\.ifm$/i
190
- tmp = open_ifm(file, map)
191
- elsif file =~ /\.inf$/i
192
- tmp = open_inform(file, map)
193
- elsif file =~ /\.t$/i or file =~ /\.t3m$/
194
- tmp = open_tads(file, map)
195
- elsif file =~ /\.gmp$/
196
- tmp = open_guemap(file, map)
197
- else
198
- tmp = open_map(file)
199
- end
200
-
201
- if not tmp.kind_of?(Map) and not tmp.kind_of?(FXMap)
202
- $stderr.puts tmp
203
- w = FXWarningBox.new( self,
204
- "#{tmp}")
205
- w.execute
206
- status "#{ERR_COULD_NOT_LOAD} '#{file}'."
207
- if make_new_map
208
- if map.close_cb
209
- @maps.delete(map)
210
- GC.start
211
- end
212
- end
213
- sleep 2
214
- return
215
- end
216
-
217
- map.copy(tmp)
218
- map.options.replace( @@default_options.merge(map.options) )
219
- map.verify_integrity
220
- map.fit
221
- map.window.create
222
- map.modified = false
223
- update_map
224
- status "#{MSG_LOADED} '#{file}'."
225
- end
226
-
227
- #
228
- # Write a message to the status bar
229
- #
230
- def status(msg)
231
- @statusbar.statusLine.text = msg
232
- end
233
-
234
- #
235
- # Returns current active map or nil if no maps
236
- #
237
- def current_map
238
- window = @mdiclient.activeChild
239
- return nil unless window
240
-
241
- @maps.each { |m|
242
- return m if m.window == window
243
- }
244
- return nil
245
- end
246
-
247
- #
248
- # Callback for Save
249
- #
250
- def save_cb(sender, sel, ptr)
251
- map = current_map
252
- return unless map
253
- map.save
254
- end
255
-
256
- #
257
- # Callback for Save As
258
- #
259
- def save_as_cb(sender, sel, ptr)
260
- map = current_map
261
- return unless map
262
- map.save_as
263
- end
264
-
265
- #
266
- # Callback used to create new map
267
- #
268
- def new_map_cb(*args)
269
- m = new_map
270
- m.window.create
271
- end
272
-
273
- #
274
- # Callback used to change language
275
- #
276
- def language_cb(sender, msg, opts)
277
- @@default_options['Language'] = LANGUAGES[sender.text]
278
-
279
- require "IFMapper/locales/#{language}/Messages.rb"
280
- recreate
281
- end
282
-
283
- #
284
- # Create a new map
285
- #
286
- def new_map
287
- mapname = "#{MSG_EMPTY_MAP} \##{@maps.size+1}"
288
- @maps.push( FXMap.new(mapname, @mdiclient, @@default_options.dup,
289
- @mdiicon, @mdimenu, MDI_NORMAL, 0, 0, 790, 500) )
290
- map = @maps[-1]
291
- map.window.connect(SEL_PAINT) {
292
- map.draw
293
- }
294
- map.window.connect(SEL_CLOSE) {
295
- if map.close_cb
296
- @maps.delete(map)
297
- end
298
- if @maps[-1]
299
- @maps[-1].update_roomlist
300
- else
301
- FXMap::no_maps
302
- end
303
- }
304
-
305
- # Make it active
306
- @mdiclient.setActiveChild(map.window)
307
- map.update_roomlist
308
- return map
309
- end
310
-
311
- #
312
- # Load the named PNG icon from a file
313
- #
314
- def load_icon(filename)
315
- begin
316
- filename = File.join("icons", filename) + ".png"
317
- icon = nil
318
- File.open(filename, "rb") { |f|
319
- icon = FXPNGIcon.new(getApp(), f.read)
320
- }
321
- icon
322
- rescue
323
- raise RuntimeError, "#{ERR_NO_ICON} #{filename}"
324
- end
325
- end
326
-
327
- #
328
- # Start a complex connection
329
- #
330
- def complex_connection_cb(sender, sel, msg)
331
- map = current_map
332
- return unless map
333
- map.complex_connection
334
- end
335
-
336
- #
337
- # Delete selected elements in map
338
- #
339
- def delete_selected_cb(sender, sel, msg)
340
- map = current_map
341
- return unless map
342
- map.delete_selected
343
- end
344
-
345
- #
346
- # Popup a printer dialog and return the settings or false if user cancels
347
- #
348
- def printer_dialog(title = MSG_PRINT_MAP)
349
- map = current_map
350
- dlg = FXPrintDialog.new(self, title + " for #{map.name}")
351
- dlg.printer.flags |= PRINT_DEST_PAPER
352
- return dlg.printer if dlg.execute != 0
353
- return false
354
- end
355
-
356
- #
357
- # Print out all the locations in map
358
- #
359
- def print_locations_cb(sender, sel, msg)
360
- map = current_map
361
- return unless map
362
-
363
- w = FXWarningBox.new( self, ERR_NO_PRINTING)
364
- w.execute
365
- return
366
-
367
- printer = printer_dialog MSG_PRINT_LOC
368
- map.print_locations( printer ) if printer
369
- end
370
-
371
- #
372
- # Export current map as an IFM file
373
- #
374
- def ifm_export_cb(sender, sel, msg)
375
- map = current_map
376
- return unless map
377
-
378
- require 'IFMapper/FXMapFileDialog'
379
- d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_IFM,
380
- [
381
- FMT_IFM
382
- ])
383
- map.export_ifm(d.filename) if d.filename != ''
384
- end
385
-
386
- #
387
- # Export current map as an Inform source file
388
- #
389
- def inform_export_cb(sender, sel, msg)
390
- map = current_map
391
- return unless map
392
-
393
- require 'IFMapper/FXMapFileDialog'
394
- d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_INFORM,
395
- [
396
- FMT_INFORM,
397
- ])
398
- map.export_inform( d.filename ) if d.filename != ''
399
- end
400
-
401
-
402
- #
403
- # Export current map as a TADs source file
404
- #
405
- def tads_export_cb(sender, sel, msg)
406
- map = current_map
407
- return unless map
408
-
409
- require 'IFMapper/TADSWriter'
410
- require 'IFMapper/FXMapFileDialog'
411
- d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_TADS,
412
- [
413
- FMT_TADS
414
- ])
415
- map.export_tads( d.filename ) if d.filename != ''
416
- end
417
-
418
-
419
- #
420
- # Export current map as Acrobat PDF
421
- #
422
- def pdf_export_cb(sender, sel, msg)
423
- map = current_map
424
- return unless map
425
-
426
- begin
427
- require 'IFMapper/PDFMapExporter'
428
- rescue LoadError => e
429
- w = FXWarningBox.new( self, "#{e}")
430
- w.execute
431
- return
432
- end
433
-
434
- require 'IFMapper/FXMapFileDialog'
435
- d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_PDF,
436
- [
437
- FMT_PDF
438
- ])
439
- if d.filename != ''
440
- map.pdf_export(d.filename)
441
- end
442
- end
443
-
444
- #
445
- # Print current map graphically
446
- #
447
- def print_cb(sender, sel, msg)
448
- map = current_map
449
- return unless map
450
-
451
- w = FXWarningBox.new( self, ERR_NO_PRINTING )
452
- w.execute
453
- return
454
- require 'IFMapper/MapPrinting'
455
-
456
- printer = printer_dialog
457
- map.print( printer ) if printer
458
- end
459
-
460
- def update_map
461
- map = current_map
462
- return unless map
463
- map.update_roomlist
464
- update_section
465
- end
466
-
467
- #
468
- # Creates the MDI (multi-document) client
469
- #
470
- def create_mdiclient
471
- # MDI Client
472
- @maps = []
473
-
474
- @mdiclient = FXMDIClient.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y)
475
- @mdiclient.connect(SEL_CHANGED) {
476
- update_map
477
- }
478
-
479
- # MDI buttons in menu:- note the message ID's!!!!!
480
- # Normally, MDI commands are simply sensitized or desensitized;
481
- # Under the @menubar, however, they're hidden if the MDI Client is
482
- # not maximized. To do this, they must have different ID's.
483
- FXMDIWindowButton.new(@menubar, @mdimenu, @mdiclient,
484
- FXMDIClient::ID_MDI_MENUWINDOW, LAYOUT_LEFT)
485
- FXMDIDeleteButton.new(@menubar, @mdiclient,
486
- FXMDIClient::ID_MDI_MENUCLOSE, FRAME_RAISED|LAYOUT_RIGHT)
487
- FXMDIRestoreButton.new(@menubar, @mdiclient,
488
- FXMDIClient::ID_MDI_MENURESTORE, FRAME_RAISED|LAYOUT_RIGHT)
489
- FXMDIMinimizeButton.new(@menubar, @mdiclient,
490
- FXMDIClient::ID_MDI_MENUMINIMIZE, FRAME_RAISED|LAYOUT_RIGHT)
491
-
492
- # Icon for MDI Child
493
- @mdiicon = load_icon("winapp")
494
-
495
- # Make MDI Window Menu
496
- @mdimenu = FXMDIMenu.new(self, @mdiclient)
497
- end
498
-
499
- #
500
- # Return the copied elements
501
- #
502
- def self.copy_buffer
503
- return @@copy_buffer
504
- end
505
-
506
- #
507
- # Copy selected elements
508
- #
509
- def self.copy_selected(map)
510
- sect = map.sections[map.section]
511
-
512
- # Get all selected rooms
513
- rooms = sect.rooms.find_all { |r| r.selected }
514
- return if rooms.size < 1
515
-
516
- # Get all selected connections
517
- links = sect.connections.find_all { |c| c.selected }
518
-
519
- # Make sure we store only those connections for
520
- # those rooms we selected
521
- delete = []
522
- links.each { |c|
523
- if not rooms.include?(c.roomA) or
524
- (c.roomB and not rooms.include?(c.roomB))
525
- delete << c
526
- end
527
- }
528
- links -= delete
529
-
530
- selection = [ rooms, links ]
531
-
532
- @@copy_buffer = selection
533
- end
534
-
535
- #
536
- # Cut selected elements
537
- #
538
- def self.cut_selected(map)
539
- FXMapperWindow::copy_selected(map)
540
- map.cut_selected
541
- end
542
-
543
- #
544
- # Paste selected elements
545
- #
546
- def self.paste_selected(map)
547
- return if not @@copy_buffer
548
- return map.navigation_warning if map.navigation
549
-
550
- sel = @@copy_buffer
551
- pos = map.find_empty_area( sel[0] )
552
- if not pos
553
- w = FXWarningBox.new( map.window, ERR_NO_FREE_ROOM)
554
- w.execute
555
- else
556
- map.clear_selection
557
-
558
- # Add rooms
559
- r_to_nr = {} # orig room to new room hash
560
- rooms = sel[0]
561
- rooms.each { |r|
562
- nr = map.new_room(r.x + pos[0], r.y + pos[1])
563
- nr.selected = true
564
- nr.copy(r) # copy the room data
565
- r_to_nr[r] = nr
566
- }
567
-
568
- if rooms.empty?
569
- # Add connections only (no rooms copied)
570
- sel[1].each { |c|
571
- exitA, exitB = c.dirs
572
- roomA = c.roomA
573
- roomB = c.roomB
574
- sect = map.sections[map.section]
575
- if not sect.rooms.include?(roomA) or
576
- (roomB and not sect.rooms.include?(roomB))
577
- next
578
- end
579
- begin
580
- nc = map.new_connection(roomA, exitA, roomB, exitB)
581
- nc.selected = true
582
- nc.dir = c.dir
583
- nc.type = c.type
584
- rescue
585
- end
586
- }
587
- else
588
- # Add connections
589
- sel[1].each { |c|
590
- exitA, exitB = c.dirs
591
- roomA = r_to_nr[c.roomA]
592
- if c.roomB
593
- roomB = r_to_nr[c.roomB]
594
- else
595
- roomB = nil
596
- end
597
- next if not roomA
598
- begin
599
- nc = map.new_connection(roomA, exitA, roomB, exitB)
600
- nc.selected = true
601
- nc.dir = c.dir
602
- nc.type = c.type
603
- rescue Section::ConnectionError => e
604
- puts c
605
- puts e
606
- end
607
- }
608
- end
609
-
610
- map.create_pathmap
611
- map.draw
612
- end
613
- end
614
-
615
- def cut_selected_cb(*o)
616
- map = current_map
617
- return unless map
618
- FXMapperWindow::cut_selected(map)
619
- end
620
-
621
- def copy_selected_cb(*o)
622
- map = current_map
623
- return unless map
624
- FXMapperWindow::copy_selected(map)
625
- end
626
-
627
- def paste_selected_cb(*o)
628
- map = current_map
629
- return if not map or not @@copy_buffer
630
- FXMapperWindow::paste_selected(map)
631
- end
632
-
633
-
634
- #
635
- # Hilite matches after a search
636
- #
637
- def hilite_matches(map, matches, re, idx = 0 )
638
- if matches.size == 0
639
- status "#{ERR_NO_MATCHES} '#{re}'."
640
- return
641
- end
642
-
643
- # sort matches by section
644
- matches.sort_by { |a| a[0] }
645
-
646
- # Jump to first section of match
647
- map.section = matches[idx][0]
648
- map.sections.each { |s|
649
- s.rooms.each { |r| r.selected = false }
650
- }
651
-
652
- matches.each { |p, r|
653
- next if p != map.section
654
- r.selected = true
655
- }
656
-
657
- num = matches.find_all { |p, r| p == matches[idx][0] }
658
- room = matches[idx][1]
659
- map.center_view_on_room( room )
660
- update_section
661
-
662
- status "'#{room.name}' #{MSG_MATCHES}. #{matches.size} #{MSG_MATCHES_IN_MAP}, #{num.size} #{MSG_MATCHES_IN_SECTION}."
663
- map.draw
664
- end
665
-
666
- #
667
- # Find location in map
668
- #
669
- def find_in_map(s, m, e)
670
- map = current_map
671
- return unless map
672
-
673
- re = /#{s.text}/
674
- matches = []
675
- (0...map.sections.size).each { |p|
676
- map.sections[p].rooms.each { |r|
677
- next unless r.name =~ re
678
- matches.push( [p, r] )
679
- }
680
- }
681
- idx = @search.index
682
- @search.index = matches.size-1 if idx >= matches.size
683
- hilite_matches(map, matches, re, @search.index)
684
- end
685
-
686
- def find_in_map_cb(s, m, e)
687
- map = current_map
688
- return unless map
689
-
690
- title = MSG_FIND_LOCATION_IN_MAP
691
- if not @search
692
- require 'IFMapper/FXSearchDialogBox'
693
- @search = FXSearchDialogBox.new(self)
694
- end
695
- @search.proc = method(:find_in_map)
696
- @search.title = title
697
- @search.text = ''
698
- @search.show
699
- end
700
-
701
- #
702
- # Find location in section
703
- #
704
- def find_in_section(s, m, e)
705
- map = current_map
706
- return unless map
707
-
708
- re = /#{s.text}/
709
- matches = []
710
- map.sections[map.section].rooms.each { |r|
711
- next unless r.name =~ re
712
- matches.push( [ map.section, r] )
713
- }
714
- hilite_matches(map, matches, re)
715
- end
716
-
717
- #
718
- # Callback
719
- #
720
- def find_in_section_cb(s, m, e)
721
- map = current_map
722
- return unless map
723
-
724
- title = MSG_FIND_LOCATION_IN_SECTION
725
- if not @search
726
- require 'IFMapper/FXSearchDialogBox'
727
- @search = FXSearchDialogBox.new(self)
728
- end
729
- @search.proc = method(:find_in_section)
730
- @search.title = title
731
- @search.text = ''
732
- @search.show
733
- end
734
-
735
- #
736
- # Find object in map
737
- #
738
- def find_object_in_map(s, m, e)
739
- map = current_map
740
- return unless map
741
-
742
- re = /#{s.text}/
743
- matches = []
744
- (0...map.sections.size).each { |p|
745
- map.sections[p].rooms.each { |r|
746
- next unless r.objects =~ re
747
- matches.push( [p, r] )
748
- }
749
- }
750
- idx = @search.index
751
- @search.index = matches.size-1 if idx >= matches.size
752
- hilite_matches(map, matches, re, @search.index)
753
- end
754
-
755
- #
756
- # Find task in map
757
- #
758
- def find_task_in_map(s, m, e)
759
- map = current_map
760
- return unless map
761
-
762
- re = /#{s.text}/
763
- matches = []
764
- (0...map.sections.size).each { |p|
765
- map.sections[p].rooms.each { |r|
766
- next unless r.tasks =~ re
767
- matches.push( [p, r] )
768
- }
769
- }
770
- idx = @search.index
771
- @search.index = matches.size-1 if idx >= matches.size
772
- hilite_matches(map, matches, re, @search.index)
773
- end
774
-
775
- #
776
- # Find object in map
777
- #
778
- def find_object_in_map_cb(s, m, e)
779
- map = current_map
780
- return unless map
781
-
782
- title = MSG_FIND_OBJECT_IN_MAP
783
- if not @search
784
- require 'IFMapper/FXSearchDialogBox'
785
- @search = FXSearchDialogBox.new(self)
786
- end
787
- @search.proc = method(:find_object_in_map)
788
- @search.title = title
789
- @search.text = ''
790
- @search.show
791
- end
792
-
793
- #
794
- # Find task in map
795
- #
796
- def find_task_in_map_cb(s, m, e)
797
- map = current_map
798
- return unless map
799
-
800
- title = MSG_FIND_TASK_IN_MAP
801
- if not @search
802
- require 'IFMapper/FXSearchDialogBox'
803
- @search = FXSearchDialogBox.new(self)
804
- end
805
- @search.proc = method(:find_task_in_map)
806
- @search.title = title
807
- @search.text = ''
808
- @search.show
809
- end
810
-
811
- #
812
- # Find task in map
813
- #
814
- def find_desc_in_map(s, m, e)
815
- map = current_map
816
- return unless map
817
-
818
- re = /#{s.text}/
819
- matches = []
820
- (0...map.sections.size).each { |p|
821
- map.sections[p].rooms.each { |r|
822
- next unless r.desc =~ re
823
- matches.push( [p, r] )
824
- }
825
- }
826
- idx = @search.index
827
- @search.index = matches.size-1 if idx >= matches.size
828
- hilite_matches(map, matches, re, @search.index)
829
- end
830
-
831
- #
832
- # Find description in map
833
- #
834
- def find_desc_in_map_cb(s, m, e)
835
- map = current_map
836
- return unless map
837
-
838
- title = MSG_FIND_DESCRIPTION_IN_MAP
839
- if not @search
840
- require 'IFMapper/FXSearchDialogBox'
841
- @search = FXSearchDialogBox.new(self)
842
- end
843
- @search.proc = method(:find_desc_in_map)
844
- @search.title = title
845
- @search.text = ''
846
- @search.show
847
- end
848
-
849
-
850
- #
851
- # Pop-up color preferences
852
- #
853
- def colors_cb(sender, id, msg)
854
- map = current_map
855
- return if not map
856
-
857
- if not @colors
858
- require 'IFMapper/FXMapColorBox'
859
- @colors = FXMapColorBox.new(self)
860
- else
861
- @colors.show
862
- end
863
- @colors.copy_from(map)
864
- end
865
-
866
- #
867
- # Unselect all
868
- #
869
- def select_none_cb( sender, id, event )
870
- map = current_map
871
- return if not map
872
- map.clear_selection
873
- end
874
-
875
- #
876
- # Select all
877
- #
878
- def select_all_cb( sender, id, event )
879
- map = current_map
880
- return if not map
881
- sect = map.sections[map.section]
882
- sect.rooms.each { |r|
883
- r.selected = true
884
- }
885
- sect.connections.each { |c|
886
- c.selected = true
887
- }
888
- end
889
-
890
- def roomlist(sender, sel, event)
891
- map = current_map
892
- return unless map
893
- map.show_roomlist
894
- end
895
-
896
-
897
- def about_cb(sender, id, event )
898
- require 'IFMapper/FXAboutDialogBox'
899
- FXAboutDialogBox.new(self, MSG_ABOUT_SOFTWARE,
900
- eval("\"#{MSG_ABOUT}\"")).execute
901
- end
902
-
903
-
904
- def create_menus
905
- # Construct these icons
906
- newdoc = load_icon("filenew")
907
- opendoc = load_icon("fileopen")
908
- savedoc = load_icon("filesave")
909
- saveasdoc = load_icon("filesaveas")
910
-
911
- # File Menu
912
- filemenu = FXMenuPane.new(self)
913
- FXMenuTitle.new(@menubar, MENU_FILE, nil, filemenu)
914
- cmd = FXMenuCommand.new(filemenu, MENU_NEW, newdoc)
915
- cmd.connect(SEL_COMMAND, method(:new_map_cb))
916
-
917
- cmd = FXMenuCommand.new(filemenu, MENU_OPEN, opendoc)
918
- cmd.connect(SEL_COMMAND, method(:open_cb))
919
- cmd = FXMenuCommand.new(filemenu, MENU_SAVE, savedoc)
920
- cmd.connect(SEL_COMMAND, method(:save_cb))
921
- cmd = FXMenuCommand.new(filemenu, MENU_SAVE_AS,
922
- saveasdoc)
923
- cmd.connect(SEL_COMMAND, method(:save_as_cb))
924
-
925
- # Export submenu
926
- submenu = FXMenuPane.new(self)
927
-
928
- cmd = FXMenuCommand.new(submenu, MENU_EXPORT_PDF, nil)
929
- cmd.connect(SEL_COMMAND, method(:pdf_export_cb))
930
-
931
- cmd = FXMenuCommand.new(submenu, MENU_EXPORT_IFM, nil)
932
- cmd.connect(SEL_COMMAND, method(:ifm_export_cb))
933
-
934
- cmd = FXMenuCommand.new(submenu, MENU_EXPORT_INFORM, nil)
935
- cmd.connect(SEL_COMMAND, method(:inform_export_cb))
936
-
937
- cmd = FXMenuCommand.new(submenu, MENU_EXPORT_TADS, nil)
938
- cmd.connect(SEL_COMMAND, method(:tads_export_cb))
939
-
940
- FXMenuCascade.new(filemenu, MENU_EXPORT, nil, submenu)
941
-
942
-
943
- submenu = FXMenuPane.new(self)
944
- cmd = FXMenuCommand.new(submenu, MENU_PRINT_MAP, nil)
945
- cmd.connect(SEL_COMMAND, method(:print_cb))
946
-
947
- cmd = FXMenuCommand.new(submenu, MENU_PRINT_LOCATIONS, nil)
948
- cmd.connect(SEL_COMMAND, method(:print_locations_cb))
949
- FXMenuCascade.new(filemenu, MENU_PRINT, nil, submenu)
950
-
951
- cmd = FXMenuCommand.new(filemenu, MENU_QUIT, nil)
952
- cmd.connect( SEL_COMMAND, method(:close_cb) )
953
-
954
- # Edit Menu
955
- editmenu = FXMenuPane.new(self)
956
- FXMenuTitle.new(@menubar, MENU_EDIT, nil, editmenu)
957
- cmd = FXMenuCommand.new(editmenu, MENU_COPY, nil)
958
- cmd.connect(SEL_COMMAND, method(:copy_selected_cb))
959
- cmd = FXMenuCommand.new(editmenu, MENU_CUT, nil)
960
- cmd.connect(SEL_COMMAND, method(:cut_selected_cb))
961
- cmd = FXMenuCommand.new(editmenu, MENU_PASTE, nil)
962
- cmd.connect(SEL_COMMAND, method(:paste_selected_cb))
963
-
964
- # Select submenu
965
- FXMenuSeparator.new(editmenu)
966
- submenu = FXMenuPane.new(self)
967
- cmd = FXMenuCommand.new( submenu, MENU_SELECT_ALL )
968
- cmd.connect(SEL_COMMAND, method(:select_all_cb))
969
- cmd = FXMenuCommand.new( submenu, MENU_SELECT_NONE )
970
- cmd.connect(SEL_COMMAND, method(:select_none_cb))
971
- FXMenuCascade.new( editmenu, MENU_SELECT, nil, submenu )
972
-
973
- # Searching submenu
974
- FXMenuSeparator.new(editmenu)
975
- submenu = FXMenuPane.new(self)
976
- cmd = FXMenuCommand.new(submenu, MENU_SEARCH_MAP)
977
- cmd.connect(SEL_COMMAND, method(:find_in_map_cb))
978
- cmd = FXMenuCommand.new(submenu, MENU_SEARCH_SECTION)
979
- cmd.connect(SEL_COMMAND, method(:find_in_section_cb))
980
- cmd = FXMenuCommand.new(submenu, MENU_SEARCH_OBJECT)
981
- cmd.connect(SEL_COMMAND, method(:find_object_in_map_cb))
982
- cmd = FXMenuCommand.new(submenu, MENU_SEARCH_TASK)
983
- cmd.connect(SEL_COMMAND, method(:find_task_in_map_cb))
984
- cmd = FXMenuCommand.new(submenu, MENU_SEARCH_DESCRIPTION)
985
- cmd.connect(SEL_COMMAND, method(:find_desc_in_map_cb))
986
- FXMenuCascade.new(editmenu, MENU_SEARCH, nil, submenu)
987
-
988
- # Complex Connection
989
- FXMenuSeparator.new(editmenu)
990
- cmd = FXMenuCommand.new(editmenu, MENU_COMPLEX_CONNECTION, nil)
991
- cmd.connect( SEL_COMMAND, method(:complex_connection_cb) )
992
-
993
- FXMenuSeparator.new(editmenu)
994
- cmd = FXMenuCommand.new(editmenu, MENU_DELETE, nil)
995
- cmd.connect( SEL_COMMAND, method(:delete_selected_cb) )
996
-
997
- # Map menu
998
- mapmenu = FXMenuPane.new(self)
999
-
1000
- cmd = FXMenuCommand.new(mapmenu, MENU_MAP_INFO)
1001
- cmd.connect(SEL_COMMAND) { map_properties }
1002
-
1003
- cmd = FXMenuCommand.new(mapmenu, MENU_ROOM_LIST)
1004
- cmd.connect(SEL_COMMAND, method(:roomlist) )
1005
-
1006
- # Automap submenu
1007
- #
1008
- submenu = FXMenuPane.new(self)
1009
- cmd = FXMenuCommand.new(submenu, MENU_AUTOMAP_START)
1010
- cmd.connect(SEL_COMMAND, method(:start_automap_cb))
1011
- cmd = FXMenuCommand.new(submenu, MENU_AUTOMAP_STOP)
1012
- cmd.connect(SEL_COMMAND, method(:stop_automap_cb))
1013
- FXMenuSeparator.new(submenu)
1014
- cmd = FXMenuCommand.new(submenu, MENU_AUTOMAP_PROPERTIES)
1015
- cmd.connect(SEL_COMMAND, method(:automap_properties_cb))
1016
- FXMenuCascade.new(mapmenu, MENU_AUTOMAP, nil, submenu)
1017
-
1018
- # Sections submenu
1019
- submenu = FXMenuPane.new(self)
1020
- cmd = FXMenuCommand.new(submenu, MENU_NEXT_SECTION)
1021
- cmd.connect(SEL_COMMAND) {
1022
- next_section
1023
- }
1024
- cmd = FXMenuCommand.new(submenu, MENU_PREVIOUS_SECTION)
1025
- cmd.connect(SEL_COMMAND) {
1026
- previous_section
1027
- }
1028
- FXMenuSeparator.new(submenu)
1029
- cmd = FXMenuCommand.new(submenu, MENU_ADD_SECTION)
1030
- cmd.connect(SEL_COMMAND) {
1031
- map = current_map
1032
- if map
1033
- map.new_section
1034
- map.modified = true
1035
- update_section
1036
- end
1037
- }
1038
- cmd = FXMenuCommand.new(submenu, MENU_RENAME_SECTION)
1039
- cmd.connect(SEL_COMMAND) {
1040
- map = current_map
1041
- if map
1042
- map.rename_section
1043
- map.modified = true
1044
- end
1045
- }
1046
- FXMenuSeparator.new(submenu)
1047
- cmd = FXMenuCommand.new(submenu, MENU_DELETE_SECTION)
1048
- cmd.connect(SEL_COMMAND) {
1049
- map = current_map
1050
- if map
1051
- map.delete_section
1052
- map.modified = true
1053
- update_section
1054
- end
1055
- }
1056
- FXMenuCascade.new(mapmenu, MENU_SECTIONS, nil, submenu)
1057
-
1058
- #
1059
- # Zoom submenu
1060
- #
1061
- submenu = FXMenuPane.new(self)
1062
- [25, 50, 75, 100, 125].each { |v|
1063
- cmd = FXMenuCommand.new(submenu, eval("\"#{MENU_ZOOM_PERCENT}\""))
1064
- cmd.connect(SEL_COMMAND) {
1065
- map = current_map
1066
- if map
1067
- map.zoom = v / 100.0
1068
- map.draw
1069
- end
1070
- }
1071
- }
1072
- FXMenuCascade.new(mapmenu, MENU_ZOOM, nil, submenu)
1073
-
1074
- submenu = FXMenuPane.new(self)
1075
-
1076
- cmd = FXMenuCheck.new(submenu, MENU_EDIT_ON_CREATION)
1077
- cmd.check = @@default_options['Edit on Creation']
1078
- cmd.connect(SEL_COMMAND) { |s, m, e|
1079
- map = current_map
1080
- if map
1081
- map.options['Edit on Creation'] = (s.check == true)
1082
- end
1083
- }
1084
- cmd.connect(SEL_UPDATE) { |s, m, e|
1085
- map = current_map
1086
- s.check = map.options['Edit on Creation'] if map
1087
- }
1088
-
1089
- cmd = FXMenuCheck.new(submenu, MENU_AUTOMATIC_CONNECTION)
1090
- cmd.check = @@default_options['Automatic Connection']
1091
- cmd.connect(SEL_COMMAND) { |s, m, e|
1092
- map = current_map
1093
- if map
1094
- map.options['Automatic Connection'] = (s.check == true)
1095
- end
1096
- }
1097
- cmd.connect(SEL_UPDATE) { |s, m, e|
1098
- map = current_map
1099
- s.check = map.options['Automatic Connection'] if map
1100
- }
1101
-
1102
- cmd = FXMenuCheck.new(submenu, MENU_CREATE_ON_CONNECTION)
1103
- cmd.check = @@default_options['Create on Connection']
1104
- cmd.connect(SEL_COMMAND) { |s, m, e|
1105
- map = current_map
1106
- map.options['Create on Connection'] = s.check if map
1107
- }
1108
- cmd.connect(SEL_UPDATE) { |s, m, e|
1109
- map = current_map
1110
- s.check = map.options['Create on Connection'] if map
1111
- }
1112
-
1113
- FXMenuCascade.new(mapmenu, MENU_OPTIONS, nil, submenu)
1114
-
1115
- ##########################
1116
- # Display submenu
1117
- #########################
1118
- submenu = FXMenuPane.new(self)
1119
- cmd = FXMenuCheck.new(submenu, MENU_USE_ROOM_CURSOR)
1120
- cmd.check = @@default_options['Use Room Cursor']
1121
- cmd.connect(SEL_COMMAND) { |s, m, e|
1122
- map = current_map
1123
- if map
1124
- map.options['Use Room Cursor'] = (s.check == true)
1125
- map.draw
1126
- end
1127
- }
1128
- cmd.connect(SEL_UPDATE) { |s, m, e|
1129
- map = current_map
1130
- s.check = map.options['Use Room Cursor'] if map
1131
- }
1132
-
1133
- cmd = FXMenuCheck.new(submenu, MENU_PATHS_AS_CURVES)
1134
- cmd.check = @@default_options['Paths as Curves']
1135
- cmd.connect(SEL_COMMAND) { |s, m, e|
1136
- map = current_map
1137
- if map
1138
- map.options['Paths as Curves'] = (s.check == true)
1139
- map.draw
1140
- end
1141
- }
1142
- cmd.connect(SEL_UPDATE) { |s, m, e|
1143
- map = current_map
1144
- s.check = map.options['Paths as Curves'] if map
1145
- }
1146
- cmd = FXMenuCheck.new(submenu, MENU_LOCATION_NUMBERS)
1147
- cmd.check = @@default_options['Location Numbers']
1148
- cmd.connect(SEL_COMMAND) { |s, m, e|
1149
- map = current_map
1150
- if map
1151
- map.options['Location Numbers'] = (s.check == true)
1152
- map.draw
1153
- end
1154
- }
1155
- cmd.connect(SEL_UPDATE) { |s, m, e|
1156
- map = current_map
1157
- s.check = map.options['Location Numbers'] if map
1158
- }
1159
-
1160
- cmd = FXMenuCheck.new(submenu, MENU_LOCATION_TASKS)
1161
- cmd.check = @@default_options['Location Tasks']
1162
- cmd.connect(SEL_COMMAND) { |s, m, e|
1163
- map = current_map
1164
- if map
1165
- map.options['Location Tasks'] = (s.check == true)
1166
- map.draw
1167
- end
1168
- }
1169
- cmd.connect(SEL_UPDATE) { |s, m, e|
1170
- map = current_map
1171
- s.check = map.options['Location Tasks'] if map
1172
- }
1173
-
1174
- cmd = FXMenuCheck.new(submenu, MENU_LOCATION_DESC)
1175
- cmd.check = @@default_options['Location Description']
1176
- cmd.connect(SEL_COMMAND) { |s, m, e|
1177
- map = current_map
1178
- if map
1179
- map.options['Location Description'] = (s.check == true)
1180
- map.draw
1181
- end
1182
- }
1183
- cmd.connect(SEL_UPDATE) { |s, m, e|
1184
- map = current_map
1185
- s.check = map.options['Location Description'] if map
1186
- }
1187
-
1188
- cmd = FXMenuCheck.new(submenu, MENU_BOXES)
1189
- cmd.check = @@default_options['Grid Boxes']
1190
- cmd.connect(SEL_COMMAND) { |s, m, e|
1191
- map = current_map
1192
- if map
1193
- map.options['Grid Boxes'] = (s.check == true)
1194
- map.draw
1195
- end
1196
- }
1197
- cmd.connect(SEL_UPDATE) { |s, m, e|
1198
- map = current_map
1199
- s.check = map.options['Grid Boxes'] if map
1200
- }
1201
-
1202
- cmd = FXMenuCheck.new(submenu, MENU_STRAIGHT_CONN)
1203
- cmd.check = @@default_options['Grid Straight Connections']
1204
- cmd.connect(SEL_COMMAND) { |s, m, e|
1205
- map = current_map
1206
- if map
1207
- map.options['Grid Straight Connections'] = (s.check == true)
1208
- map.draw
1209
- end
1210
- }
1211
- cmd.connect(SEL_UPDATE) { |s, m, e|
1212
- map = current_map
1213
- s.check = map.options['Grid Straight Connections'] if map
1214
- }
1215
-
1216
- cmd = FXMenuCheck.new(submenu, MENU_DIAGONAL_CONN)
1217
- cmd.check = @@default_options['Grid Diagonal Connections']
1218
- cmd.connect(SEL_COMMAND) { |s, m, e|
1219
- map = current_map
1220
- if map
1221
- map.options['Grid Diagonal Connections'] = s.check
1222
- map.draw
1223
- end
1224
- }
1225
- cmd.connect(SEL_UPDATE) { |s, m, e|
1226
- map = current_map
1227
- s.check = map.options['Grid Diagonal Connections'] if map
1228
- }
1229
-
1230
- FXMenuCascade.new(mapmenu, MENU_DISPLAY, nil, submenu)
1231
-
1232
- submenu = FXMenuPane.new(self)
1233
-
1234
- cmd = FXMenuCommand.new(submenu, MENU_COLORS)
1235
- cmd.connect(SEL_COMMAND, method(:colors_cb))
1236
-
1237
- # langmenu = FXMenuPane.new(self)
1238
- # LANGUAGES.each { |k, v|
1239
- # next unless File.exists?( "lib/IFMapper/locales/#{v}/Messages.rb" )
1240
- # cmd = FXMenuCheck.new(langmenu, k)
1241
- # cmd.connect(SEL_COMMAND, method(:language_cb))
1242
- # }
1243
-
1244
- # FXMenuCascade.new(mapmenu, MENU_LANGUAGE, nil, langmenu)
1245
-
1246
-
1247
- FXMenuSeparator.new(submenu)
1248
- cmd = FXMenuCommand.new(submenu, MENU_SAVE_PREFS)
1249
- cmd.connect(SEL_COMMAND) {
1250
- map = current_map
1251
- map.options.write if map
1252
- }
1253
- FXMenuCascade.new(mapmenu, MENU_PREFS, nil, submenu)
1254
-
1255
- FXMenuTitle.new(@menubar, MENU_MAP, nil, mapmenu)
1256
-
1257
- # Window menu
1258
- windowmenu = FXMenuPane.new(self)
1259
- FXMenuCommand.new(windowmenu, MENU_TILE_HORIZONTALLY, nil,
1260
- @mdiclient, FXMDIClient::ID_MDI_TILEHORIZONTAL)
1261
- FXMenuCommand.new(windowmenu, MENU_TILE_VERTICALLY, nil,
1262
- @mdiclient, FXMDIClient::ID_MDI_TILEVERTICAL)
1263
- FXMenuCommand.new(windowmenu, MENU_CASCADE, nil,
1264
- @mdiclient, FXMDIClient::ID_MDI_CASCADE)
1265
- FXMenuCommand.new(windowmenu, MENU_CLOSE, nil,
1266
- @mdiclient, FXMDIClient::ID_MDI_CLOSE)
1267
- sep1 = FXMenuSeparator.new(windowmenu)
1268
- sep1.setTarget(@mdiclient)
1269
- sep1.setSelector(FXMDIClient::ID_MDI_ANY)
1270
- FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_1)
1271
- FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_2)
1272
- FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_3)
1273
- FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_4)
1274
- FXMenuCommand.new(windowmenu, MENU_OTHERS, nil, @mdiclient,
1275
- FXMDIClient::ID_MDI_OVER_5)
1276
- FXMenuTitle.new(@menubar, MENU_WINDOW, nil, windowmenu)
1277
-
1278
- # Help menu
1279
- helpmenu = FXMenuPane.new(self)
1280
- cmd = FXMenuCommand.new(helpmenu, MENU_HOTKEYS, nil)
1281
- cmd.connect(SEL_COMMAND, method(:hotkeys))
1282
- cmd = FXMenuCommand.new(helpmenu, MENU_INSTRUCTIONS, nil)
1283
- cmd.connect(SEL_COMMAND, method(:docs))
1284
- FXMenuSeparator.new(helpmenu)
1285
- cmd = FXMenuCommand.new(helpmenu, MENU_ABOUT, nil)
1286
- cmd.connect(SEL_COMMAND, method(:about_cb))
1287
-
1288
- cmd = FXMenuCommand.new(helpmenu, MENU_RESOURCE, nil)
1289
- cmd.connect(SEL_COMMAND) {
1290
- require 'IFMapper/FXMapFileDialog'
1291
- file = FXMapFileDialog.new(self, "Resource a Ruby File",
1292
- ['Ruby File (*.rb)']).filename
1293
- if file != ''
1294
- begin
1295
- Kernel.load file
1296
- rescue => e
1297
- p e
1298
- end
1299
- end
1300
- }
1301
- FXMenuTitle.new(@menubar, MENU_HELP, nil, helpmenu)
1302
- end
1303
-
1304
- def language
1305
- return @@default_options['Language']
1306
- end
1307
-
1308
- def docs(*opts)
1309
- browsers = [ 'firefox', 'opera', 'explorer' ]
1310
- address = 'docs/' + language + '/start.html'
1311
- status "#{MSG_OPENING_WEB_PAGE} #{address}..."
1312
- ok = false
1313
- browsers.each { |cmd|
1314
- if RUBY_PLATFORM =~ /mswin/
1315
- ok = system("start #{cmd} #{address}")
1316
- else
1317
- ok = system("#{cmd} #{address} &")
1318
- end
1319
- break if ok
1320
- }
1321
- if not ok
1322
- status ERR_COULD_NOT_OPEN_WEB_BROWSER
1323
- end
1324
- end
1325
-
1326
-
1327
- def hotkeys(*opts)
1328
- require 'IFMapper/FXAboutDialogBox'
1329
- FXAboutDialogBox.new(self, BOX_HOTKEYS, MSG_HOTKEYS).show
1330
- end
1331
-
1332
- def create_toolbar(toolbar)
1333
-
1334
- # Construct these icons
1335
- newdoc = load_icon("filenew")
1336
- opendoc = load_icon("fileopen")
1337
- savedoc = load_icon("filesave")
1338
- saveasdoc = load_icon("filesaveas")
1339
-
1340
- # File manipulation
1341
- cmd = FXButton.new(toolbar, ICON_NEW, newdoc, nil, 0,
1342
- FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1343
- cmd.connect(SEL_COMMAND, method(:new_map_cb))
1344
-
1345
- cmd = FXButton.new(toolbar, ICON_OPEN, opendoc, nil, 0,
1346
- FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1347
- cmd.connect(SEL_COMMAND, method(:open_cb))
1348
-
1349
- cmd = FXButton.new(toolbar, ICON_SAVE, savedoc, nil, 0,
1350
- FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1351
- cmd.connect(SEL_COMMAND, method(:save_cb))
1352
- cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1353
- map = current_map
1354
- message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1355
- sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1356
- }
1357
- cmd = FXButton.new(toolbar, ICON_SAVE_AS,
1358
- saveasdoc, nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1359
- cmd.connect(SEL_COMMAND, method(:save_as_cb))
1360
- cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1361
- map = current_map
1362
- message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1363
- sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1364
- }
1365
-
1366
- # Print
1367
- FXFrame.new(toolbar,
1368
- LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 4, 20)
1369
- cmd = FXButton.new(toolbar, ICON_PRINT,
1370
- load_icon("printicon"), @mdiclient, FXGLViewer::ID_PRINT_IMAGE,
1371
- BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1372
- cmd.connect(SEL_COMMAND, method(:print_cb))
1373
- cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1374
- map = current_map
1375
- message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1376
- sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1377
- }
1378
-
1379
- # Editing
1380
- FXFrame.new(toolbar,
1381
- LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 4, 20)
1382
- cmd = FXButton.new(toolbar, ICON_CUT, load_icon("cut"), @mdiclient,
1383
- FXGLViewer::ID_CUT_SEL, (BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|
1384
- LAYOUT_TOP|LAYOUT_LEFT))
1385
- cmd.connect(SEL_COMMAND, method(:cut_selected_cb))
1386
- cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1387
- map = current_map
1388
- message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1389
- sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1390
- }
1391
- cmd = FXButton.new(toolbar, ICON_COPY, load_icon("copy"), @mdiclient,
1392
- FXGLViewer::ID_COPY_SEL, (BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|
1393
- LAYOUT_TOP|LAYOUT_LEFT))
1394
- cmd.connect(SEL_COMMAND, method(:copy_selected_cb))
1395
- cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1396
- map = current_map
1397
- message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1398
- sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1399
- }
1400
- cmd = FXButton.new(toolbar, ICON_PASTE, load_icon("paste"), @mdiclient,
1401
- FXGLViewer::ID_PASTE_SEL, (BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|
1402
- LAYOUT_TOP|LAYOUT_LEFT))
1403
- cmd.connect(SEL_COMMAND, method(:paste_selected_cb))
1404
- cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1405
- map = current_map
1406
- message = (map and @@copy_buffer) ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1407
- sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1408
- }
1409
-
1410
- # Zooming
1411
- FXFrame.new(toolbar,
1412
- LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 4, 20)
1413
- cmd = FXButton.new(toolbar, ICON_ZOOM_IN, load_icon("zoom"), @mdiclient,
1414
- 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1415
- cmd.connect(SEL_COMMAND) { zoom_in }
1416
-
1417
- cmd = FXButton.new(toolbar, ICON_ZOOM_OUT, load_icon("zoom"), @mdiclient,
1418
- 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1419
- cmd.connect(SEL_COMMAND) { zoom_out }
1420
-
1421
-
1422
- # Section travel
1423
- frame = FXHorizontalFrame.new(toolbar,
1424
- LAYOUT_RIGHT|FRAME_THICK|FRAME_RAISED)
1425
- cmd = FXButton.new(frame, ICON_PREV_SECTION, load_icon("prevpage"),
1426
- @mdiclient,
1427
- 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1428
- cmd.connect(SEL_COMMAND) { previous_section }
1429
-
1430
- @section = FXTextField.new(frame, 5, nil, 0,
1431
- TEXTFIELD_INTEGER|LAYOUT_FILL_ROW)
1432
- @section.text = '1'
1433
- @section.connect(SEL_COMMAND) { |s,m,e|
1434
- v = s.text.to_i
1435
- map = current_map
1436
- if map
1437
- map.section = v - 1
1438
- map.draw
1439
- update_section
1440
- end
1441
- }
1442
- @section.connect(SEL_UPDATE) { |s,m,e|
1443
- v = s.text.to_i
1444
- map = current_map
1445
- update_section if map
1446
- }
1447
-
1448
- cmd = FXButton.new(frame, ICON_NEXT_SECTION, load_icon("nextpage"),
1449
- @mdiclient,
1450
- 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1451
- cmd.connect(SEL_COMMAND) { next_section }
1452
- end
1453
-
1454
- #
1455
- # Update section # in toolbar widget
1456
- #
1457
- def update_section
1458
- map = current_map
1459
- return unless map
1460
- @section.text = (map.section + 1).to_s
1461
- end
1462
-
1463
- #
1464
- # Go to next section in current map
1465
- #
1466
- def next_section
1467
- map = current_map
1468
- map.next_section if map
1469
- update_section
1470
- end
1471
-
1472
- #
1473
- # Go to previous section in current map
1474
- #
1475
- def previous_section
1476
- map = current_map
1477
- map.previous_section if map
1478
- update_section
1479
- end
1480
-
1481
- #
1482
- # Zoom in into current map
1483
- #
1484
- def zoom_in
1485
- map = current_map
1486
- if map
1487
- map.zoom_in
1488
- map.draw
1489
- end
1490
- end
1491
-
1492
- #
1493
- # Zoom out from current map
1494
- #
1495
- def zoom_out
1496
- map = current_map
1497
- if map
1498
- map.zoom_out
1499
- map.draw
1500
- end
1501
- end
1502
-
1503
- #
1504
- # Bring up the map property requester for current map
1505
- #
1506
- def map_properties
1507
- map = current_map
1508
- map.properties if map
1509
- end
1510
-
1511
- #
1512
- # In case of crash or runtime error, autosave all maps, so user
1513
- # does not loose any data.
1514
- #
1515
- def autosave
1516
- @maps.each { |m|
1517
- m.save
1518
- }
1519
- end
1520
-
1521
-
1522
- def create_widgets
1523
- # Menubar
1524
- @menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
1525
-
1526
- FXHorizontalSeparator.new(self,
1527
- LAYOUT_SIDE_TOP|SEPARATOR_GROOVE|LAYOUT_FILL_X)
1528
- toolbar = FXToolBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X,
1529
- 0, 0, 0, 0, 4, 4, 0, 0, 0, 0)
1530
-
1531
- # Status bar
1532
- @statusbar = FXStatusBar.new(self,
1533
- LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|
1534
- STATUSBAR_WITH_DRAGCORNER)
1535
-
1536
-
1537
- create_mdiclient
1538
- create_menus
1539
- create_toolbar(toolbar)
1540
- new_map
1541
-
1542
- self.connect(SEL_CLOSE, method(:close_cb))
1543
- show
1544
- end
1545
-
1546
- def initialize(app)
1547
- super(app, eval("\"#{TITLE}\""), nil, nil, DECOR_ALL, 0, 0, 800, 600)
1548
-
1549
- create_widgets
1550
-
1551
- # Trap CTRL-C signals and exit nicely
1552
- trap('SIGINT') {
1553
- close_cb
1554
- exit(0)
1555
- }
1556
- end
1557
-
1558
- def close_cb(*args)
1559
- exit = true
1560
- @maps.each { |m|
1561
- if not m.close_cb
1562
- exit = false
1563
- break
1564
- else
1565
- @maps.delete(m)
1566
- end
1567
- }
1568
- self.close if exit
1569
- end
1570
-
1571
- end
1
+
2
+
3
+ begin
4
+ $rubygems = false
5
+ require 'rubygems'
6
+ $rubygems = true
7
+ rescue LoadError
8
+ end
9
+
10
+ def no_fox
11
+ $stderr.puts ERR_NO_FOX
12
+ if $rubygems
13
+ $stderr.puts ERR_HAS_GEMS
14
+ end
15
+ exit(1)
16
+ end
17
+
18
+ def get_fox
19
+ ##### ARRRGH!!!! Why does Lyle keep changing the fxruby name on each
20
+ ##### release!
21
+ foxes = [ 'fox16', 'fox14', 'fox12', 'fox' ]
22
+ foxes.each { |fox|
23
+ begin
24
+ require "#{fox}"
25
+ require "#{fox}/colors"
26
+ break
27
+ rescue LoadError
28
+ no_fox if fox == foxes[-1]
29
+ end
30
+ }
31
+
32
+ # verify fxruby version
33
+ ver, rev, = Fox::fxrubyversion().split('.')
34
+ no_fox if ver.to_i < 1 or rev.to_i < 2
35
+ end
36
+
37
+
38
+ get_fox
39
+ include Fox
40
+
41
+ require 'IFMapper/FXMap'
42
+ require 'IFMapper/FXMapperSettings'
43
+ require 'IFMapper/FXWarningBox'
44
+
45
+
46
+ class FXMapperWindow < FXMainWindow
47
+
48
+ PROGRAM_NAME = "Interactive Fiction Mapper"
49
+ VERSION = '1.0.6'
50
+ AUTHOR = "Gonzalo Garramuño"
51
+
52
+ @@copy_buffer = nil
53
+ @@default_options = FXMapperSettings.new
54
+
55
+ LANGUAGES = {
56
+ 'English' => 'en',
57
+ 'Español' => 'es',
58
+ # todo1
59
+ 'Deutsch' => 'de',
60
+ 'Italiano' => 'it',
61
+ 'Fran�ais' => 'fr',
62
+ # todo2
63
+ 'Japanese' => 'ja',
64
+ 'Chinese' => 'ch',
65
+ 'Korean' => 'ko',
66
+ 'Arabic' => 'ar',
67
+ }
68
+
69
+ def open_map(file)
70
+ tmp = nil
71
+ begin
72
+ f = File.open(file, 'rb')
73
+ tmp = Marshal.load(f)
74
+ f.close
75
+ tmp.filename = file
76
+ rescue => e
77
+ tmp = e
78
+ end
79
+ return tmp
80
+ end
81
+
82
+ def open_ifm(file, map)
83
+ require 'IFMapper/IFMReader'
84
+ begin
85
+ IFMReader.new(file, map)
86
+ rescue => e
87
+ return "#{e} #{e.backtrace}"
88
+ end
89
+ return map
90
+ end
91
+
92
+ def open_tads(file, map)
93
+ require 'IFMapper/TADSReader'
94
+ begin
95
+ TADSReader.new(file, map)
96
+ rescue => e
97
+ return "#{e}"
98
+ end
99
+ return map
100
+ end
101
+
102
+ def open_inform(file, map)
103
+ require 'IFMapper/InformReader'
104
+ begin
105
+ InformReader.new(file, map)
106
+ rescue => e
107
+ return "#{e}"
108
+ end
109
+ return map
110
+ end
111
+
112
+ def open_guemap(file, map)
113
+ require 'IFMapper/GUEReader'
114
+ begin
115
+ GUEReader.new(file, map)
116
+ rescue => e
117
+ return "#{e}"
118
+ end
119
+ return map
120
+ end
121
+
122
+ #
123
+ # Start automapping from a transcript
124
+ #
125
+ def start_automap_cb(sender, sel, ptr)
126
+ map = current_map
127
+ return if not map
128
+ map.start_automap
129
+ end
130
+
131
+ #
132
+ # Properties of the automapper callback
133
+ #
134
+ def automap_properties_cb(sender, sel, ptr)
135
+ map = current_map
136
+ return if not map or not map.automap
137
+ map.automap.properties(true)
138
+ end
139
+
140
+ #
141
+ # Stop automapping from a transcript
142
+ #
143
+ def stop_automap_cb(sender, sel, ptr)
144
+ map = current_map
145
+ return if not map
146
+ map.stop_automap
147
+ end
148
+
149
+
150
+ #
151
+ # Callback to Open File
152
+ #
153
+ def open_cb(sender, sel, ptr)
154
+ require 'IFMapper/FXMapFileDialog'
155
+ file = FXMapFileDialog.new(self, MSG_LOAD_MAP).filename
156
+ return if file == ''
157
+
158
+ # First, make sure we don't have it loaded already...
159
+ @maps.each { |m|
160
+ if m.filename == file
161
+ @mdiclient.setActiveChild(m.window)
162
+ return
163
+ end
164
+ }
165
+
166
+ # Then, check if we have a single and empty map.
167
+ # If so, we can just use that one to load the file in.
168
+ # If not, we need to create a new map
169
+ make_new_map = false
170
+ if @maps.size == 1
171
+ @maps[0].sections.each { |p|
172
+ if p.rooms.size != 0
173
+ make_new_map = true
174
+ break
175
+ end
176
+ }
177
+ else
178
+ make_new_map = true
179
+ end
180
+
181
+ if make_new_map
182
+ map = new_map
183
+ else
184
+ map = @maps[0]
185
+ end
186
+ status "#{MSG_LOADING} '#{file}'..."
187
+
188
+ tmp = nil
189
+ if file =~ /\.ifm$/i
190
+ tmp = open_ifm(file, map)
191
+ elsif file =~ /\.inf$/i
192
+ tmp = open_inform(file, map)
193
+ elsif file =~ /\.t$/i or file =~ /\.t3m$/
194
+ tmp = open_tads(file, map)
195
+ elsif file =~ /\.gmp$/
196
+ tmp = open_guemap(file, map)
197
+ else
198
+ tmp = open_map(file)
199
+ end
200
+
201
+ if not tmp.kind_of?(Map) and not tmp.kind_of?(FXMap)
202
+ $stderr.puts tmp
203
+ w = FXWarningBox.new( self,
204
+ "#{tmp}")
205
+ w.execute
206
+ status "#{ERR_COULD_NOT_LOAD} '#{file}'."
207
+ if make_new_map
208
+ if map.close_cb
209
+ @maps.delete(map)
210
+ GC.start
211
+ end
212
+ end
213
+ sleep 2
214
+ return
215
+ end
216
+
217
+ map.copy(tmp)
218
+ map.options.replace( @@default_options.merge(map.options) )
219
+ map.verify_integrity
220
+ map.fit
221
+ map.window.create
222
+ map.modified = false
223
+ update_map
224
+ status "#{MSG_LOADED} '#{file}'."
225
+ end
226
+
227
+ #
228
+ # Write a message to the status bar
229
+ #
230
+ def status(msg)
231
+ @statusbar.statusLine.text = msg
232
+ end
233
+
234
+ #
235
+ # Returns current active map or nil if no maps
236
+ #
237
+ def current_map
238
+ window = @mdiclient.activeChild
239
+ return nil unless window
240
+
241
+ @maps.each { |m|
242
+ return m if m.window == window
243
+ }
244
+ return nil
245
+ end
246
+
247
+ #
248
+ # Callback for Save
249
+ #
250
+ def save_cb(sender, sel, ptr)
251
+ map = current_map
252
+ return unless map
253
+ map.save
254
+ end
255
+
256
+ #
257
+ # Callback for Save As
258
+ #
259
+ def save_as_cb(sender, sel, ptr)
260
+ map = current_map
261
+ return unless map
262
+ map.save_as
263
+ end
264
+
265
+ #
266
+ # Callback used to create new map
267
+ #
268
+ def new_map_cb(*args)
269
+ m = new_map
270
+ m.window.create
271
+ end
272
+
273
+ #
274
+ # Callback used to change language
275
+ #
276
+ def language_cb(sender, msg, opts)
277
+ @@default_options['Language'] = LANGUAGES[sender.text]
278
+
279
+ require "IFMapper/locales/#{language}/Messages.rb"
280
+ recreate
281
+ end
282
+
283
+ #
284
+ # Create a new map
285
+ #
286
+ def new_map
287
+ mapname = "#{MSG_EMPTY_MAP} \##{@maps.size+1}"
288
+ @maps.push( FXMap.new(mapname, @mdiclient, @@default_options.dup,
289
+ @mdiicon, @mdimenu, MDI_NORMAL, 0, 0, 790, 500) )
290
+ map = @maps[-1]
291
+ map.window.connect(SEL_PAINT) {
292
+ map.draw
293
+ }
294
+ map.window.connect(SEL_CLOSE) {
295
+ if map.close_cb
296
+ @maps.delete(map)
297
+ end
298
+ if @maps[-1]
299
+ @maps[-1].update_roomlist
300
+ else
301
+ FXMap::no_maps
302
+ end
303
+ }
304
+
305
+ # Make it active
306
+ @mdiclient.setActiveChild(map.window)
307
+ map.update_roomlist
308
+ return map
309
+ end
310
+
311
+ #
312
+ # Load the named PNG icon from a file
313
+ #
314
+ def load_icon(filename)
315
+ begin
316
+ filename = File.join("icons", filename) + ".png"
317
+ icon = nil
318
+ File.open(filename, "rb") { |f|
319
+ icon = FXPNGIcon.new(getApp(), f.read)
320
+ }
321
+ icon
322
+ rescue
323
+ raise RuntimeError, "#{ERR_NO_ICON} #{filename}"
324
+ end
325
+ end
326
+
327
+ #
328
+ # Start a complex connection
329
+ #
330
+ def complex_connection_cb(sender, sel, msg)
331
+ map = current_map
332
+ return unless map
333
+ map.complex_connection
334
+ end
335
+
336
+ #
337
+ # Delete selected elements in map
338
+ #
339
+ def delete_selected_cb(sender, sel, msg)
340
+ map = current_map
341
+ return unless map
342
+ map.delete_selected
343
+ end
344
+
345
+ #
346
+ # Popup a printer dialog and return the settings or false if user cancels
347
+ #
348
+ def printer_dialog(title = MSG_PRINT_MAP)
349
+ map = current_map
350
+ dlg = FXPrintDialog.new(self, title + " for #{map.name}")
351
+ dlg.printer.flags |= PRINT_DEST_PAPER
352
+ return dlg.printer if dlg.execute != 0
353
+ return false
354
+ end
355
+
356
+ #
357
+ # Print out all the locations in map
358
+ #
359
+ def print_locations_cb(sender, sel, msg)
360
+ map = current_map
361
+ return unless map
362
+
363
+ w = FXWarningBox.new( self, ERR_NO_PRINTING)
364
+ w.execute
365
+ return
366
+
367
+ printer = printer_dialog MSG_PRINT_LOC
368
+ map.print_locations( printer ) if printer
369
+ end
370
+
371
+ #
372
+ # Export current map as an IFM file
373
+ #
374
+ def ifm_export_cb(sender, sel, msg)
375
+ map = current_map
376
+ return unless map
377
+
378
+ require 'IFMapper/FXMapFileDialog'
379
+ d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_IFM,
380
+ [
381
+ FMT_IFM
382
+ ])
383
+ map.export_ifm(d.filename) if d.filename != ''
384
+ end
385
+
386
+ #
387
+ # Export current map as an Inform source file
388
+ #
389
+ def inform_export_cb(sender, sel, msg)
390
+ map = current_map
391
+ return unless map
392
+
393
+ require 'IFMapper/FXMapFileDialog'
394
+ d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_INFORM,
395
+ [
396
+ FMT_INFORM,
397
+ ])
398
+ map.export_inform( d.filename ) if d.filename != ''
399
+ end
400
+
401
+
402
+ #
403
+ # Export current map as a TADs source file
404
+ #
405
+ def tads_export_cb(sender, sel, msg)
406
+ map = current_map
407
+ return unless map
408
+
409
+ require 'IFMapper/TADSWriter'
410
+ require 'IFMapper/FXMapFileDialog'
411
+ d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_TADS,
412
+ [
413
+ FMT_TADS
414
+ ])
415
+ map.export_tads( d.filename ) if d.filename != ''
416
+ end
417
+
418
+
419
+ #
420
+ # Export current map as Acrobat PDF
421
+ #
422
+ def pdf_export_cb(sender, sel, msg)
423
+ map = current_map
424
+ return unless map
425
+
426
+ begin
427
+ require 'IFMapper/PDFMapExporter'
428
+ rescue LoadError => e
429
+ w = FXWarningBox.new( self, "#{e}")
430
+ w.execute
431
+ return
432
+ end
433
+
434
+ # PRE: Let's ask for a page size and orientation for the PDF
435
+ # and whether the user wants to include location numbers
436
+ map.pdfpapersize = 0
437
+ map.pdflocationnos = 1
438
+ require 'IFMapper/FXPDFMapExporterOptionsDialogBox'
439
+ cmd = FXPDFMapExporterOptionsDialogBox.new(self, MSG_SAVE_MAP_AS_PDF,
440
+ map).execute
441
+
442
+ return if cmd == 0
443
+
444
+ require 'IFMapper/FXMapFileDialog'
445
+ d = FXMapFileDialog.new(self, MSG_SAVE_MAP_AS_PDF,
446
+ [
447
+ FMT_PDF
448
+ ])
449
+ if d.filename != ''
450
+ map.pdf_export(d.filename)
451
+ end
452
+ end
453
+
454
+ #
455
+ # Print current map graphically
456
+ #
457
+ def print_cb(sender, sel, msg)
458
+ map = current_map
459
+ return unless map
460
+
461
+ w = FXWarningBox.new( self, ERR_NO_PRINTING )
462
+ w.execute
463
+ return
464
+ require 'IFMapper/MapPrinting'
465
+
466
+ printer = printer_dialog
467
+ map.print( printer ) if printer
468
+ end
469
+
470
+ def update_map
471
+ map = current_map
472
+ return unless map
473
+ map.update_roomlist
474
+ update_section
475
+ end
476
+
477
+ #
478
+ # Creates the MDI (multi-document) client
479
+ #
480
+ def create_mdiclient
481
+ # MDI Client
482
+ @maps = []
483
+
484
+ @mdiclient = FXMDIClient.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y)
485
+ @mdiclient.connect(SEL_CHANGED) {
486
+ update_map
487
+ }
488
+
489
+ # MDI buttons in menu:- note the message ID's!!!!!
490
+ # Normally, MDI commands are simply sensitized or desensitized;
491
+ # Under the @menubar, however, they're hidden if the MDI Client is
492
+ # not maximized. To do this, they must have different ID's.
493
+ FXMDIWindowButton.new(@menubar, @mdimenu, @mdiclient,
494
+ FXMDIClient::ID_MDI_MENUWINDOW, LAYOUT_LEFT)
495
+ FXMDIDeleteButton.new(@menubar, @mdiclient,
496
+ FXMDIClient::ID_MDI_MENUCLOSE, FRAME_RAISED|LAYOUT_RIGHT)
497
+ FXMDIRestoreButton.new(@menubar, @mdiclient,
498
+ FXMDIClient::ID_MDI_MENURESTORE, FRAME_RAISED|LAYOUT_RIGHT)
499
+ FXMDIMinimizeButton.new(@menubar, @mdiclient,
500
+ FXMDIClient::ID_MDI_MENUMINIMIZE, FRAME_RAISED|LAYOUT_RIGHT)
501
+
502
+ # Icon for MDI Child
503
+ @mdiicon = load_icon("winapp")
504
+
505
+ # Make MDI Window Menu
506
+ @mdimenu = FXMDIMenu.new(self, @mdiclient)
507
+ end
508
+
509
+ #
510
+ # Return the copied elements
511
+ #
512
+ def self.copy_buffer
513
+ return @@copy_buffer
514
+ end
515
+
516
+ #
517
+ # Copy selected elements
518
+ #
519
+ def self.copy_selected(map)
520
+ sect = map.sections[map.section]
521
+
522
+ # Get all selected rooms
523
+ rooms = sect.rooms.find_all { |r| r.selected }
524
+ return if rooms.size < 1
525
+
526
+ # Get all selected connections
527
+ links = sect.connections.find_all { |c| c.selected }
528
+
529
+ # Make sure we store only those connections for
530
+ # those rooms we selected
531
+ delete = []
532
+ links.each { |c|
533
+ if not rooms.include?(c.roomA) or
534
+ (c.roomB and not rooms.include?(c.roomB))
535
+ delete << c
536
+ end
537
+ }
538
+ links -= delete
539
+
540
+ selection = [ rooms, links ]
541
+
542
+ @@copy_buffer = selection
543
+ end
544
+
545
+ #
546
+ # Cut selected elements
547
+ #
548
+ def self.cut_selected(map)
549
+ FXMapperWindow::copy_selected(map)
550
+ map.cut_selected
551
+ end
552
+
553
+ #
554
+ # Paste selected elements
555
+ #
556
+ def self.paste_selected(map)
557
+ return if not @@copy_buffer
558
+ return map.navigation_warning if map.navigation
559
+
560
+ sel = @@copy_buffer
561
+ pos = map.find_empty_area( sel[0] )
562
+ if not pos
563
+ w = FXWarningBox.new( map.window, ERR_NO_FREE_ROOM)
564
+ w.execute
565
+ else
566
+ map.clear_selection
567
+
568
+ # Add rooms
569
+ r_to_nr = {} # orig room to new room hash
570
+ rooms = sel[0]
571
+ rooms.each { |r|
572
+ nr = map.new_room(r.x + pos[0], r.y + pos[1])
573
+ nr.selected = true
574
+ nr.copy(r) # copy the room data
575
+ r_to_nr[r] = nr
576
+ }
577
+
578
+ if rooms.empty?
579
+ # Add connections only (no rooms copied)
580
+ sel[1].each { |c|
581
+ exitA, exitB = c.dirs
582
+ roomA = c.roomA
583
+ roomB = c.roomB
584
+ sect = map.sections[map.section]
585
+ if not sect.rooms.include?(roomA) or
586
+ (roomB and not sect.rooms.include?(roomB))
587
+ next
588
+ end
589
+ begin
590
+ nc = map.new_connection(roomA, exitA, roomB, exitB)
591
+ nc.selected = true
592
+ nc.dir = c.dir
593
+ nc.type = c.type
594
+ rescue
595
+ end
596
+ }
597
+ else
598
+ # Add connections
599
+ sel[1].each { |c|
600
+ exitA, exitB = c.dirs
601
+ roomA = r_to_nr[c.roomA]
602
+ if c.roomB
603
+ roomB = r_to_nr[c.roomB]
604
+ else
605
+ roomB = nil
606
+ end
607
+ next if not roomA
608
+ begin
609
+ nc = map.new_connection(roomA, exitA, roomB, exitB)
610
+ nc.selected = true
611
+ nc.dir = c.dir
612
+ nc.type = c.type
613
+ rescue Section::ConnectionError => e
614
+ puts c
615
+ puts e
616
+ end
617
+ }
618
+ end
619
+
620
+ map.create_pathmap
621
+ map.draw
622
+ end
623
+ end
624
+
625
+ def cut_selected_cb(*o)
626
+ map = current_map
627
+ return unless map
628
+ FXMapperWindow::cut_selected(map)
629
+ end
630
+
631
+ def copy_selected_cb(*o)
632
+ map = current_map
633
+ return unless map
634
+ FXMapperWindow::copy_selected(map)
635
+ end
636
+
637
+ def paste_selected_cb(*o)
638
+ map = current_map
639
+ return if not map or not @@copy_buffer
640
+ FXMapperWindow::paste_selected(map)
641
+ end
642
+
643
+
644
+ #
645
+ # Hilite matches after a search
646
+ #
647
+ def hilite_matches(map, matches, re, idx = 0 )
648
+ if matches.size == 0
649
+ status "#{ERR_NO_MATCHES} '#{re}'."
650
+ return
651
+ end
652
+
653
+ # sort matches by section
654
+ matches.sort_by { |a| a[0] }
655
+
656
+ # Jump to first section of match
657
+ map.section = matches[idx][0]
658
+ map.sections.each { |s|
659
+ s.rooms.each { |r| r.selected = false }
660
+ }
661
+
662
+ matches.each { |p, r|
663
+ next if p != map.section
664
+ r.selected = true
665
+ }
666
+
667
+ num = matches.find_all { |p, r| p == matches[idx][0] }
668
+ room = matches[idx][1]
669
+ map.center_view_on_room( room )
670
+ update_section
671
+
672
+ status "'#{room.name}' #{MSG_MATCHES}. #{matches.size} #{MSG_MATCHES_IN_MAP}, #{num.size} #{MSG_MATCHES_IN_SECTION}."
673
+ map.draw
674
+ end
675
+
676
+ #
677
+ # Find location in map
678
+ #
679
+ def find_in_map(s, m, e)
680
+ map = current_map
681
+ return unless map
682
+
683
+ re = /#{s.text}/
684
+ matches = []
685
+ (0...map.sections.size).each { |p|
686
+ map.sections[p].rooms.each { |r|
687
+ next unless r.name =~ re
688
+ matches.push( [p, r] )
689
+ }
690
+ }
691
+ idx = @search.index
692
+ @search.index = matches.size-1 if idx >= matches.size
693
+ hilite_matches(map, matches, re, @search.index)
694
+ end
695
+
696
+ def find_in_map_cb(s, m, e)
697
+ map = current_map
698
+ return unless map
699
+
700
+ title = MSG_FIND_LOCATION_IN_MAP
701
+ if not @search
702
+ require 'IFMapper/FXSearchDialogBox'
703
+ @search = FXSearchDialogBox.new(self)
704
+ end
705
+ @search.proc = method(:find_in_map)
706
+ @search.title = title
707
+ @search.text = ''
708
+ @search.show
709
+ end
710
+
711
+ #
712
+ # Find location in section
713
+ #
714
+ def find_in_section(s, m, e)
715
+ map = current_map
716
+ return unless map
717
+
718
+ re = /#{s.text}/
719
+ matches = []
720
+ map.sections[map.section].rooms.each { |r|
721
+ next unless r.name =~ re
722
+ matches.push( [ map.section, r] )
723
+ }
724
+ hilite_matches(map, matches, re)
725
+ end
726
+
727
+ #
728
+ # Callback
729
+ #
730
+ def find_in_section_cb(s, m, e)
731
+ map = current_map
732
+ return unless map
733
+
734
+ title = MSG_FIND_LOCATION_IN_SECTION
735
+ if not @search
736
+ require 'IFMapper/FXSearchDialogBox'
737
+ @search = FXSearchDialogBox.new(self)
738
+ end
739
+ @search.proc = method(:find_in_section)
740
+ @search.title = title
741
+ @search.text = ''
742
+ @search.show
743
+ end
744
+
745
+ #
746
+ # Find object in map
747
+ #
748
+ def find_object_in_map(s, m, e)
749
+ map = current_map
750
+ return unless map
751
+
752
+ re = /#{s.text}/
753
+ matches = []
754
+ (0...map.sections.size).each { |p|
755
+ map.sections[p].rooms.each { |r|
756
+ next unless r.objects =~ re
757
+ matches.push( [p, r] )
758
+ }
759
+ }
760
+ idx = @search.index
761
+ @search.index = matches.size-1 if idx >= matches.size
762
+ hilite_matches(map, matches, re, @search.index)
763
+ end
764
+
765
+ #
766
+ # Find task in map
767
+ #
768
+ def find_task_in_map(s, m, e)
769
+ map = current_map
770
+ return unless map
771
+
772
+ re = /#{s.text}/
773
+ matches = []
774
+ (0...map.sections.size).each { |p|
775
+ map.sections[p].rooms.each { |r|
776
+ next unless r.tasks =~ re
777
+ matches.push( [p, r] )
778
+ }
779
+ }
780
+ idx = @search.index
781
+ @search.index = matches.size-1 if idx >= matches.size
782
+ hilite_matches(map, matches, re, @search.index)
783
+ end
784
+
785
+ #
786
+ # Find object in map
787
+ #
788
+ def find_object_in_map_cb(s, m, e)
789
+ map = current_map
790
+ return unless map
791
+
792
+ title = MSG_FIND_OBJECT_IN_MAP
793
+ if not @search
794
+ require 'IFMapper/FXSearchDialogBox'
795
+ @search = FXSearchDialogBox.new(self)
796
+ end
797
+ @search.proc = method(:find_object_in_map)
798
+ @search.title = title
799
+ @search.text = ''
800
+ @search.show
801
+ end
802
+
803
+ #
804
+ # Find task in map
805
+ #
806
+ def find_task_in_map_cb(s, m, e)
807
+ map = current_map
808
+ return unless map
809
+
810
+ title = MSG_FIND_TASK_IN_MAP
811
+ if not @search
812
+ require 'IFMapper/FXSearchDialogBox'
813
+ @search = FXSearchDialogBox.new(self)
814
+ end
815
+ @search.proc = method(:find_task_in_map)
816
+ @search.title = title
817
+ @search.text = ''
818
+ @search.show
819
+ end
820
+
821
+ #
822
+ # Find task in map
823
+ #
824
+ def find_desc_in_map(s, m, e)
825
+ map = current_map
826
+ return unless map
827
+
828
+ re = /#{s.text}/
829
+ matches = []
830
+ (0...map.sections.size).each { |p|
831
+ map.sections[p].rooms.each { |r|
832
+ next unless r.desc =~ re
833
+ matches.push( [p, r] )
834
+ }
835
+ }
836
+ idx = @search.index
837
+ @search.index = matches.size-1 if idx >= matches.size
838
+ hilite_matches(map, matches, re, @search.index)
839
+ end
840
+
841
+ #
842
+ # Find description in map
843
+ #
844
+ def find_desc_in_map_cb(s, m, e)
845
+ map = current_map
846
+ return unless map
847
+
848
+ title = MSG_FIND_DESCRIPTION_IN_MAP
849
+ if not @search
850
+ require 'IFMapper/FXSearchDialogBox'
851
+ @search = FXSearchDialogBox.new(self)
852
+ end
853
+ @search.proc = method(:find_desc_in_map)
854
+ @search.title = title
855
+ @search.text = ''
856
+ @search.show
857
+ end
858
+
859
+
860
+ #
861
+ # Pop-up color preferences
862
+ #
863
+ def colors_cb(sender, id, msg)
864
+ map = current_map
865
+ return if not map
866
+
867
+ if not @colors
868
+ require 'IFMapper/FXMapColorBox'
869
+ @colors = FXMapColorBox.new(self)
870
+ else
871
+ @colors.show
872
+ end
873
+ @colors.copy_from(map)
874
+ end
875
+
876
+ #
877
+ # Unselect all
878
+ #
879
+ def select_none_cb( sender, id, event )
880
+ map = current_map
881
+ return if not map
882
+ map.clear_selection
883
+ end
884
+
885
+ #
886
+ # Select all
887
+ #
888
+ def select_all_cb( sender, id, event )
889
+ map = current_map
890
+ return if not map
891
+ sect = map.sections[map.section]
892
+ sect.rooms.each { |r|
893
+ r.selected = true
894
+ }
895
+ sect.connections.each { |c|
896
+ c.selected = true
897
+ }
898
+ end
899
+
900
+ def roomlist(sender, sel, event)
901
+ map = current_map
902
+ return unless map
903
+ map.show_roomlist
904
+ end
905
+
906
+ def itemlist(sender, sel, event)
907
+ map = current_map
908
+ return unless map
909
+ map.show_itemlist
910
+ end
911
+
912
+ def about_cb(sender, id, event )
913
+ require 'IFMapper/FXAboutDialogBox'
914
+ FXAboutDialogBox.new(self, MSG_ABOUT_SOFTWARE,
915
+ eval("\"#{MSG_ABOUT}\"")).execute
916
+ end
917
+
918
+
919
+ def create_menus
920
+ # Construct these icons
921
+ newdoc = load_icon("filenew")
922
+ opendoc = load_icon("fileopen")
923
+ savedoc = load_icon("filesave")
924
+ saveasdoc = load_icon("filesaveas")
925
+
926
+ # File Menu
927
+ filemenu = FXMenuPane.new(self)
928
+ FXMenuTitle.new(@menubar, MENU_FILE, nil, filemenu)
929
+ cmd = FXMenuCommand.new(filemenu, MENU_NEW, newdoc)
930
+ cmd.connect(SEL_COMMAND, method(:new_map_cb))
931
+
932
+ cmd = FXMenuCommand.new(filemenu, MENU_OPEN, opendoc)
933
+ cmd.connect(SEL_COMMAND, method(:open_cb))
934
+ cmd = FXMenuCommand.new(filemenu, MENU_SAVE, savedoc)
935
+ cmd.connect(SEL_COMMAND, method(:save_cb))
936
+ cmd = FXMenuCommand.new(filemenu, MENU_SAVE_AS,
937
+ saveasdoc)
938
+ cmd.connect(SEL_COMMAND, method(:save_as_cb))
939
+
940
+ # Export submenu
941
+ submenu = FXMenuPane.new(self)
942
+
943
+ cmd = FXMenuCommand.new(submenu, MENU_EXPORT_PDF, nil)
944
+ cmd.connect(SEL_COMMAND, method(:pdf_export_cb))
945
+
946
+ cmd = FXMenuCommand.new(submenu, MENU_EXPORT_IFM, nil)
947
+ cmd.connect(SEL_COMMAND, method(:ifm_export_cb))
948
+
949
+ cmd = FXMenuCommand.new(submenu, MENU_EXPORT_INFORM, nil)
950
+ cmd.connect(SEL_COMMAND, method(:inform_export_cb))
951
+
952
+ cmd = FXMenuCommand.new(submenu, MENU_EXPORT_TADS, nil)
953
+ cmd.connect(SEL_COMMAND, method(:tads_export_cb))
954
+
955
+ FXMenuCascade.new(filemenu, MENU_EXPORT, nil, submenu)
956
+
957
+
958
+ submenu = FXMenuPane.new(self)
959
+ cmd = FXMenuCommand.new(submenu, MENU_PRINT_MAP, nil)
960
+ cmd.connect(SEL_COMMAND, method(:print_cb))
961
+
962
+ cmd = FXMenuCommand.new(submenu, MENU_PRINT_LOCATIONS, nil)
963
+ cmd.connect(SEL_COMMAND, method(:print_locations_cb))
964
+ FXMenuCascade.new(filemenu, MENU_PRINT, nil, submenu)
965
+
966
+ cmd = FXMenuCommand.new(filemenu, MENU_QUIT, nil)
967
+ cmd.connect( SEL_COMMAND, method(:close_cb) )
968
+
969
+ # Edit Menu
970
+ editmenu = FXMenuPane.new(self)
971
+ FXMenuTitle.new(@menubar, MENU_EDIT, nil, editmenu)
972
+ cmd = FXMenuCommand.new(editmenu, MENU_COPY, nil)
973
+ cmd.connect(SEL_COMMAND, method(:copy_selected_cb))
974
+ cmd = FXMenuCommand.new(editmenu, MENU_CUT, nil)
975
+ cmd.connect(SEL_COMMAND, method(:cut_selected_cb))
976
+ cmd = FXMenuCommand.new(editmenu, MENU_PASTE, nil)
977
+ cmd.connect(SEL_COMMAND, method(:paste_selected_cb))
978
+
979
+ # Select submenu
980
+ FXMenuSeparator.new(editmenu)
981
+ submenu = FXMenuPane.new(self)
982
+ cmd = FXMenuCommand.new( submenu, MENU_SELECT_ALL )
983
+ cmd.connect(SEL_COMMAND, method(:select_all_cb))
984
+ cmd = FXMenuCommand.new( submenu, MENU_SELECT_NONE )
985
+ cmd.connect(SEL_COMMAND, method(:select_none_cb))
986
+ FXMenuCascade.new( editmenu, MENU_SELECT, nil, submenu )
987
+
988
+ # Searching submenu
989
+ FXMenuSeparator.new(editmenu)
990
+ submenu = FXMenuPane.new(self)
991
+ cmd = FXMenuCommand.new(submenu, MENU_SEARCH_MAP)
992
+ cmd.connect(SEL_COMMAND, method(:find_in_map_cb))
993
+ cmd = FXMenuCommand.new(submenu, MENU_SEARCH_SECTION)
994
+ cmd.connect(SEL_COMMAND, method(:find_in_section_cb))
995
+ cmd = FXMenuCommand.new(submenu, MENU_SEARCH_OBJECT)
996
+ cmd.connect(SEL_COMMAND, method(:find_object_in_map_cb))
997
+ cmd = FXMenuCommand.new(submenu, MENU_SEARCH_TASK)
998
+ cmd.connect(SEL_COMMAND, method(:find_task_in_map_cb))
999
+ cmd = FXMenuCommand.new(submenu, MENU_SEARCH_DESCRIPTION)
1000
+ cmd.connect(SEL_COMMAND, method(:find_desc_in_map_cb))
1001
+ FXMenuCascade.new(editmenu, MENU_SEARCH, nil, submenu)
1002
+
1003
+ # Complex Connection
1004
+ FXMenuSeparator.new(editmenu)
1005
+ cmd = FXMenuCommand.new(editmenu, MENU_COMPLEX_CONNECTION, nil)
1006
+ cmd.connect( SEL_COMMAND, method(:complex_connection_cb) )
1007
+
1008
+ FXMenuSeparator.new(editmenu)
1009
+ cmd = FXMenuCommand.new(editmenu, MENU_DELETE, nil)
1010
+ cmd.connect( SEL_COMMAND, method(:delete_selected_cb) )
1011
+
1012
+ # Map menu
1013
+ mapmenu = FXMenuPane.new(self)
1014
+
1015
+ cmd = FXMenuCommand.new(mapmenu, MENU_MAP_INFO)
1016
+ cmd.connect(SEL_COMMAND) { map_properties }
1017
+
1018
+ cmd = FXMenuCommand.new(mapmenu, MENU_ROOM_LIST)
1019
+ cmd.connect(SEL_COMMAND, method(:roomlist) )
1020
+
1021
+ cmd = FXMenuCommand.new(mapmenu, MENU_ITEM_LIST)
1022
+ cmd.connect(SEL_COMMAND, method(:itemlist) )
1023
+
1024
+ # Automap submenu
1025
+ #
1026
+ submenu = FXMenuPane.new(self)
1027
+ cmd = FXMenuCommand.new(submenu, MENU_AUTOMAP_START)
1028
+ cmd.connect(SEL_COMMAND, method(:start_automap_cb))
1029
+ cmd = FXMenuCommand.new(submenu, MENU_AUTOMAP_STOP)
1030
+ cmd.connect(SEL_COMMAND, method(:stop_automap_cb))
1031
+ FXMenuSeparator.new(submenu)
1032
+ cmd = FXMenuCommand.new(submenu, MENU_AUTOMAP_PROPERTIES)
1033
+ cmd.connect(SEL_COMMAND, method(:automap_properties_cb))
1034
+ FXMenuCascade.new(mapmenu, MENU_AUTOMAP, nil, submenu)
1035
+
1036
+ # Sections submenu
1037
+ submenu = FXMenuPane.new(self)
1038
+ cmd = FXMenuCommand.new(submenu, MENU_NEXT_SECTION)
1039
+ cmd.connect(SEL_COMMAND) {
1040
+ next_section
1041
+ }
1042
+ cmd = FXMenuCommand.new(submenu, MENU_PREVIOUS_SECTION)
1043
+ cmd.connect(SEL_COMMAND) {
1044
+ previous_section
1045
+ }
1046
+ FXMenuSeparator.new(submenu)
1047
+ cmd = FXMenuCommand.new(submenu, MENU_ADD_SECTION)
1048
+ cmd.connect(SEL_COMMAND) {
1049
+ map = current_map
1050
+ if map
1051
+ map.new_section
1052
+ map.modified = true
1053
+ update_section
1054
+ end
1055
+ }
1056
+ cmd = FXMenuCommand.new(submenu, MENU_RENAME_SECTION)
1057
+ cmd.connect(SEL_COMMAND) {
1058
+ map = current_map
1059
+ if map
1060
+ map.rename_section
1061
+ map.modified = true
1062
+ end
1063
+ }
1064
+ FXMenuSeparator.new(submenu)
1065
+ cmd = FXMenuCommand.new(submenu, MENU_DELETE_SECTION)
1066
+ cmd.connect(SEL_COMMAND) {
1067
+ map = current_map
1068
+ if map
1069
+ map.delete_section
1070
+ map.modified = true
1071
+ update_section
1072
+ end
1073
+ }
1074
+ FXMenuCascade.new(mapmenu, MENU_SECTIONS, nil, submenu)
1075
+
1076
+ #
1077
+ # Zoom submenu
1078
+ #
1079
+ submenu = FXMenuPane.new(self)
1080
+ [25, 50, 75, 100, 125].each { |v|
1081
+ cmd = FXMenuCommand.new(submenu, eval("\"#{MENU_ZOOM_PERCENT}\""))
1082
+ cmd.connect(SEL_COMMAND) {
1083
+ map = current_map
1084
+ if map
1085
+ map.zoom = v / 100.0
1086
+ map.draw
1087
+ end
1088
+ }
1089
+ }
1090
+ FXMenuCascade.new(mapmenu, MENU_ZOOM, nil, submenu)
1091
+
1092
+ submenu = FXMenuPane.new(self)
1093
+
1094
+ cmd = FXMenuCheck.new(submenu, MENU_EDIT_ON_CREATION)
1095
+ cmd.check = @@default_options['Edit on Creation']
1096
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1097
+ map = current_map
1098
+ if map
1099
+ map.options['Edit on Creation'] = (s.check == true)
1100
+ end
1101
+ }
1102
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1103
+ map = current_map
1104
+ s.check = map.options['Edit on Creation'] if map
1105
+ }
1106
+
1107
+ cmd = FXMenuCheck.new(submenu, MENU_AUTOMATIC_CONNECTION)
1108
+ cmd.check = @@default_options['Automatic Connection']
1109
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1110
+ map = current_map
1111
+ if map
1112
+ map.options['Automatic Connection'] = (s.check == true)
1113
+ end
1114
+ }
1115
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1116
+ map = current_map
1117
+ s.check = map.options['Automatic Connection'] if map
1118
+ }
1119
+
1120
+ cmd = FXMenuCheck.new(submenu, MENU_CREATE_ON_CONNECTION)
1121
+ cmd.check = @@default_options['Create on Connection']
1122
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1123
+ map = current_map
1124
+ map.options['Create on Connection'] = s.check if map
1125
+ }
1126
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1127
+ map = current_map
1128
+ s.check = map.options['Create on Connection'] if map
1129
+ }
1130
+
1131
+ FXMenuCascade.new(mapmenu, MENU_OPTIONS, nil, submenu)
1132
+
1133
+ ##########################
1134
+ # Display submenu
1135
+ #########################
1136
+ submenu = FXMenuPane.new(self)
1137
+ cmd = FXMenuCheck.new(submenu, MENU_USE_ROOM_CURSOR)
1138
+ cmd.check = @@default_options['Use Room Cursor']
1139
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1140
+ map = current_map
1141
+ if map
1142
+ map.options['Use Room Cursor'] = (s.check == true)
1143
+ map.draw
1144
+ end
1145
+ }
1146
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1147
+ map = current_map
1148
+ s.check = map.options['Use Room Cursor'] if map
1149
+ }
1150
+
1151
+ cmd = FXMenuCheck.new(submenu, MENU_PATHS_AS_CURVES)
1152
+ cmd.check = @@default_options['Paths as Curves']
1153
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1154
+ map = current_map
1155
+ if map
1156
+ map.options['Paths as Curves'] = (s.check == true)
1157
+ map.draw
1158
+ end
1159
+ }
1160
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1161
+ map = current_map
1162
+ s.check = map.options['Paths as Curves'] if map
1163
+ }
1164
+ cmd = FXMenuCheck.new(submenu, MENU_LOCATION_NUMBERS)
1165
+ cmd.check = @@default_options['Location Numbers']
1166
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1167
+ map = current_map
1168
+ if map
1169
+ map.options['Location Numbers'] = (s.check == true)
1170
+ map.draw
1171
+ end
1172
+ }
1173
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1174
+ map = current_map
1175
+ s.check = map.options['Location Numbers'] if map
1176
+ }
1177
+
1178
+ cmd = FXMenuCheck.new(submenu, MENU_LOCATION_TASKS)
1179
+ cmd.check = @@default_options['Location Tasks']
1180
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1181
+ map = current_map
1182
+ if map
1183
+ map.options['Location Tasks'] = (s.check == true)
1184
+ map.draw
1185
+ end
1186
+ }
1187
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1188
+ map = current_map
1189
+ s.check = map.options['Location Tasks'] if map
1190
+ }
1191
+
1192
+ cmd = FXMenuCheck.new(submenu, MENU_LOCATION_DESC)
1193
+ cmd.check = @@default_options['Location Description']
1194
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1195
+ map = current_map
1196
+ if map
1197
+ map.options['Location Description'] = (s.check == true)
1198
+ map.draw
1199
+ end
1200
+ }
1201
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1202
+ map = current_map
1203
+ s.check = map.options['Location Description'] if map
1204
+ }
1205
+
1206
+ cmd = FXMenuCheck.new(submenu, MENU_BOXES)
1207
+ cmd.check = @@default_options['Grid Boxes']
1208
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1209
+ map = current_map
1210
+ if map
1211
+ map.options['Grid Boxes'] = (s.check == true)
1212
+ map.draw
1213
+ end
1214
+ }
1215
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1216
+ map = current_map
1217
+ s.check = map.options['Grid Boxes'] if map
1218
+ }
1219
+
1220
+ cmd = FXMenuCheck.new(submenu, MENU_STRAIGHT_CONN)
1221
+ cmd.check = @@default_options['Grid Straight Connections']
1222
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1223
+ map = current_map
1224
+ if map
1225
+ map.options['Grid Straight Connections'] = (s.check == true)
1226
+ map.draw
1227
+ end
1228
+ }
1229
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1230
+ map = current_map
1231
+ s.check = map.options['Grid Straight Connections'] if map
1232
+ }
1233
+
1234
+ cmd = FXMenuCheck.new(submenu, MENU_DIAGONAL_CONN)
1235
+ cmd.check = @@default_options['Grid Diagonal Connections']
1236
+ cmd.connect(SEL_COMMAND) { |s, m, e|
1237
+ map = current_map
1238
+ if map
1239
+ map.options['Grid Diagonal Connections'] = s.check
1240
+ map.draw
1241
+ end
1242
+ }
1243
+ cmd.connect(SEL_UPDATE) { |s, m, e|
1244
+ map = current_map
1245
+ s.check = map.options['Grid Diagonal Connections'] if map
1246
+ }
1247
+
1248
+ FXMenuCascade.new(mapmenu, MENU_DISPLAY, nil, submenu)
1249
+
1250
+ submenu = FXMenuPane.new(self)
1251
+
1252
+ cmd = FXMenuCommand.new(submenu, MENU_COLORS)
1253
+ cmd.connect(SEL_COMMAND, method(:colors_cb))
1254
+
1255
+ # langmenu = FXMenuPane.new(self)
1256
+ # LANGUAGES.each { |k, v|
1257
+ # next unless File.exists?( "lib/IFMapper/locales/#{v}/Messages.rb" )
1258
+ # cmd = FXMenuCheck.new(langmenu, k)
1259
+ # cmd.connect(SEL_COMMAND, method(:language_cb))
1260
+ # }
1261
+
1262
+ # FXMenuCascade.new(mapmenu, MENU_LANGUAGE, nil, langmenu)
1263
+
1264
+
1265
+ FXMenuSeparator.new(submenu)
1266
+ cmd = FXMenuCommand.new(submenu, MENU_SAVE_PREFS)
1267
+ cmd.connect(SEL_COMMAND) {
1268
+ map = current_map
1269
+ map.options.write if map
1270
+ }
1271
+ FXMenuCascade.new(mapmenu, MENU_PREFS, nil, submenu)
1272
+
1273
+ FXMenuTitle.new(@menubar, MENU_MAP, nil, mapmenu)
1274
+
1275
+ # Window menu
1276
+ windowmenu = FXMenuPane.new(self)
1277
+ FXMenuCommand.new(windowmenu, MENU_TILE_HORIZONTALLY, nil,
1278
+ @mdiclient, FXMDIClient::ID_MDI_TILEHORIZONTAL)
1279
+ FXMenuCommand.new(windowmenu, MENU_TILE_VERTICALLY, nil,
1280
+ @mdiclient, FXMDIClient::ID_MDI_TILEVERTICAL)
1281
+ FXMenuCommand.new(windowmenu, MENU_CASCADE, nil,
1282
+ @mdiclient, FXMDIClient::ID_MDI_CASCADE)
1283
+ FXMenuCommand.new(windowmenu, MENU_CLOSE, nil,
1284
+ @mdiclient, FXMDIClient::ID_MDI_CLOSE)
1285
+ sep1 = FXMenuSeparator.new(windowmenu)
1286
+ sep1.setTarget(@mdiclient)
1287
+ sep1.setSelector(FXMDIClient::ID_MDI_ANY)
1288
+ FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_1)
1289
+ FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_2)
1290
+ FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_3)
1291
+ FXMenuCommand.new(windowmenu, nil, nil, @mdiclient, FXMDIClient::ID_MDI_4)
1292
+ FXMenuCommand.new(windowmenu, MENU_OTHERS, nil, @mdiclient,
1293
+ FXMDIClient::ID_MDI_OVER_5)
1294
+ FXMenuTitle.new(@menubar, MENU_WINDOW, nil, windowmenu)
1295
+
1296
+ # Help menu
1297
+ helpmenu = FXMenuPane.new(self)
1298
+ cmd = FXMenuCommand.new(helpmenu, MENU_HOTKEYS, nil)
1299
+ cmd.connect(SEL_COMMAND, method(:hotkeys))
1300
+ cmd = FXMenuCommand.new(helpmenu, MENU_INSTRUCTIONS, nil)
1301
+ cmd.connect(SEL_COMMAND, method(:docs))
1302
+ FXMenuSeparator.new(helpmenu)
1303
+ cmd = FXMenuCommand.new(helpmenu, MENU_ABOUT, nil)
1304
+ cmd.connect(SEL_COMMAND, method(:about_cb))
1305
+
1306
+ cmd = FXMenuCommand.new(helpmenu, MENU_RESOURCE, nil)
1307
+ cmd.connect(SEL_COMMAND) {
1308
+ require 'IFMapper/FXMapFileDialog'
1309
+ file = FXMapFileDialog.new(self, "Resource a Ruby File",
1310
+ ['Ruby File (*.rb)']).filename
1311
+ if file != ''
1312
+ begin
1313
+ Kernel.load file
1314
+ rescue => e
1315
+ p e
1316
+ end
1317
+ end
1318
+ }
1319
+ FXMenuTitle.new(@menubar, MENU_HELP, nil, helpmenu)
1320
+ end
1321
+
1322
+ def language
1323
+ return @@default_options['Language']
1324
+ end
1325
+
1326
+ def docs(*opts)
1327
+ browsers = [ 'firefox', 'opera', 'explorer' ]
1328
+ address = 'docs/' + language + '/start.html'
1329
+ status "#{MSG_OPENING_WEB_PAGE} #{address}..."
1330
+ ok = false
1331
+ browsers.each { |cmd|
1332
+ if RUBY_PLATFORM =~ /mswin/
1333
+ ok = system("start #{cmd} #{address}")
1334
+ else
1335
+ ok = system("#{cmd} #{address} &")
1336
+ end
1337
+ break if ok
1338
+ }
1339
+ if not ok
1340
+ status ERR_COULD_NOT_OPEN_WEB_BROWSER
1341
+ end
1342
+ end
1343
+
1344
+
1345
+ def hotkeys(*opts)
1346
+ require 'IFMapper/FXAboutDialogBox'
1347
+ FXAboutDialogBox.new(self, BOX_HOTKEYS, MSG_HOTKEYS).show
1348
+ end
1349
+
1350
+ def create_toolbar(toolbar)
1351
+
1352
+ # Construct these icons
1353
+ newdoc = load_icon("filenew")
1354
+ opendoc = load_icon("fileopen")
1355
+ savedoc = load_icon("filesave")
1356
+ saveasdoc = load_icon("filesaveas")
1357
+
1358
+ # File manipulation
1359
+ cmd = FXButton.new(toolbar, ICON_NEW, newdoc, nil, 0,
1360
+ FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1361
+ cmd.connect(SEL_COMMAND, method(:new_map_cb))
1362
+
1363
+ cmd = FXButton.new(toolbar, ICON_OPEN, opendoc, nil, 0,
1364
+ FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1365
+ cmd.connect(SEL_COMMAND, method(:open_cb))
1366
+
1367
+ cmd = FXButton.new(toolbar, ICON_SAVE, savedoc, nil, 0,
1368
+ FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1369
+ cmd.connect(SEL_COMMAND, method(:save_cb))
1370
+ cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1371
+ map = current_map
1372
+ message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1373
+ sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1374
+ }
1375
+ cmd = FXButton.new(toolbar, ICON_SAVE_AS,
1376
+ saveasdoc, nil, 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1377
+ cmd.connect(SEL_COMMAND, method(:save_as_cb))
1378
+ cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1379
+ map = current_map
1380
+ message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1381
+ sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1382
+ }
1383
+
1384
+ # Print
1385
+ FXFrame.new(toolbar,
1386
+ LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 4, 20)
1387
+ cmd = FXButton.new(toolbar, ICON_PRINT,
1388
+ load_icon("printicon"), @mdiclient, FXGLViewer::ID_PRINT_IMAGE,
1389
+ BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1390
+ cmd.connect(SEL_COMMAND, method(:print_cb))
1391
+ cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1392
+ map = current_map
1393
+ message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1394
+ sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1395
+ }
1396
+
1397
+ # Editing
1398
+ FXFrame.new(toolbar,
1399
+ LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 4, 20)
1400
+ cmd = FXButton.new(toolbar, ICON_CUT, load_icon("cut"), @mdiclient,
1401
+ FXGLViewer::ID_CUT_SEL, (BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|
1402
+ LAYOUT_TOP|LAYOUT_LEFT))
1403
+ cmd.connect(SEL_COMMAND, method(:cut_selected_cb))
1404
+ cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1405
+ map = current_map
1406
+ message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1407
+ sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1408
+ }
1409
+ cmd = FXButton.new(toolbar, ICON_COPY, load_icon("copy"), @mdiclient,
1410
+ FXGLViewer::ID_COPY_SEL, (BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|
1411
+ LAYOUT_TOP|LAYOUT_LEFT))
1412
+ cmd.connect(SEL_COMMAND, method(:copy_selected_cb))
1413
+ cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1414
+ map = current_map
1415
+ message = map ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1416
+ sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1417
+ }
1418
+ cmd = FXButton.new(toolbar, ICON_PASTE, load_icon("paste"), @mdiclient,
1419
+ FXGLViewer::ID_PASTE_SEL, (BUTTON_AUTOGRAY|FRAME_THICK|FRAME_RAISED|
1420
+ LAYOUT_TOP|LAYOUT_LEFT))
1421
+ cmd.connect(SEL_COMMAND, method(:paste_selected_cb))
1422
+ cmd.connect(SEL_UPDATE) { |sender, sel, ptr|
1423
+ map = current_map
1424
+ message = (map and @@copy_buffer) ? FXWindow::ID_ENABLE : FXWindow::ID_DISABLE
1425
+ sender.handle(self, MKUINT(message, SEL_COMMAND), nil)
1426
+ }
1427
+
1428
+ # Zooming
1429
+ FXFrame.new(toolbar,
1430
+ LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 4, 20)
1431
+ cmd = FXButton.new(toolbar, ICON_ZOOM_IN, load_icon("zoom"), @mdiclient,
1432
+ 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1433
+ cmd.connect(SEL_COMMAND) { zoom_in }
1434
+
1435
+ cmd = FXButton.new(toolbar, ICON_ZOOM_OUT, load_icon("zoom"), @mdiclient,
1436
+ 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1437
+ cmd.connect(SEL_COMMAND) { zoom_out }
1438
+
1439
+
1440
+ # Section travel
1441
+ frame = FXHorizontalFrame.new(toolbar,
1442
+ LAYOUT_RIGHT|FRAME_THICK|FRAME_RAISED)
1443
+ cmd = FXButton.new(frame, ICON_PREV_SECTION, load_icon("prevpage"),
1444
+ @mdiclient,
1445
+ 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1446
+ cmd.connect(SEL_COMMAND) { previous_section }
1447
+
1448
+ @section = FXTextField.new(frame, 5, nil, 0,
1449
+ TEXTFIELD_INTEGER|LAYOUT_FILL_ROW)
1450
+ @section.text = '1'
1451
+ @section.connect(SEL_COMMAND) { |s,m,e|
1452
+ v = s.text.to_i
1453
+ map = current_map
1454
+ if map
1455
+ map.section = v - 1
1456
+ map.draw
1457
+ update_section
1458
+ end
1459
+ }
1460
+ @section.connect(SEL_UPDATE) { |s,m,e|
1461
+ v = s.text.to_i
1462
+ map = current_map
1463
+ update_section if map
1464
+ }
1465
+
1466
+ cmd = FXButton.new(frame, ICON_NEXT_SECTION, load_icon("nextpage"),
1467
+ @mdiclient,
1468
+ 0, FRAME_THICK|FRAME_RAISED|LAYOUT_TOP|LAYOUT_LEFT)
1469
+ cmd.connect(SEL_COMMAND) { next_section }
1470
+ end
1471
+
1472
+ #
1473
+ # Update section # in toolbar widget
1474
+ #
1475
+ def update_section
1476
+ map = current_map
1477
+ return unless map
1478
+ @section.text = (map.section + 1).to_s
1479
+ end
1480
+
1481
+ #
1482
+ # Go to next section in current map
1483
+ #
1484
+ def next_section
1485
+ map = current_map
1486
+ map.next_section if map
1487
+ update_section
1488
+ end
1489
+
1490
+ #
1491
+ # Go to previous section in current map
1492
+ #
1493
+ def previous_section
1494
+ map = current_map
1495
+ map.previous_section if map
1496
+ update_section
1497
+ end
1498
+
1499
+ #
1500
+ # Zoom in into current map
1501
+ #
1502
+ def zoom_in
1503
+ map = current_map
1504
+ if map
1505
+ map.zoom_in
1506
+ map.draw
1507
+ end
1508
+ end
1509
+
1510
+ #
1511
+ # Zoom out from current map
1512
+ #
1513
+ def zoom_out
1514
+ map = current_map
1515
+ if map
1516
+ map.zoom_out
1517
+ map.draw
1518
+ end
1519
+ end
1520
+
1521
+ #
1522
+ # Bring up the map property requester for current map
1523
+ #
1524
+ def map_properties
1525
+ map = current_map
1526
+ map.properties if map
1527
+ end
1528
+
1529
+ #
1530
+ # In case of crash or runtime error, autosave all maps, so user
1531
+ # does not loose any data.
1532
+ #
1533
+ def autosave
1534
+ @maps.each { |m|
1535
+ m.save
1536
+ }
1537
+ end
1538
+
1539
+
1540
+ def create_widgets
1541
+ # Menubar
1542
+ @menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
1543
+
1544
+ FXHorizontalSeparator.new(self,
1545
+ LAYOUT_SIDE_TOP|SEPARATOR_GROOVE|LAYOUT_FILL_X)
1546
+ toolbar = FXToolBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X,
1547
+ 0, 0, 0, 0, 4, 4, 0, 0, 0, 0)
1548
+
1549
+ # Status bar
1550
+ @statusbar = FXStatusBar.new(self,
1551
+ LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|
1552
+ STATUSBAR_WITH_DRAGCORNER)
1553
+
1554
+
1555
+ create_mdiclient
1556
+ create_menus
1557
+ create_toolbar(toolbar)
1558
+ new_map
1559
+
1560
+ self.connect(SEL_CLOSE, method(:close_cb))
1561
+ show
1562
+ end
1563
+
1564
+ def initialize(app)
1565
+ super(app, eval("\"#{TITLE}\""), nil, nil, DECOR_ALL, 0, 0, 800, 600)
1566
+
1567
+ @colors = nil
1568
+ @mdimenu = nil
1569
+
1570
+ create_widgets
1571
+
1572
+ # Trap CTRL-C signals and exit nicely
1573
+ trap('SIGINT') {
1574
+ close_cb
1575
+ exit(0)
1576
+ }
1577
+ end
1578
+
1579
+ def close_cb(*args)
1580
+ exit = true
1581
+ @maps.each { |m|
1582
+ if not m.close_cb
1583
+ exit = false
1584
+ break
1585
+ else
1586
+ @maps.delete(m)
1587
+ end
1588
+ }
1589
+ self.close if exit
1590
+ end
1591
+
1592
+ end