gui.rb 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. require "flexlay.rb"
  2. class SuperTuxGUI
  3. quit_button = nil
  4. menu = nil
  5. selector_window = nil
  6. tileselector = nil
  7. objectselector = nil
  8. attr_reader :tileselector, :editor_map, :workspace, :minimap, :recent_files_menu, :gui
  9. def get_component()
  10. return @gui.get_component()
  11. end
  12. def initialize(width, height)
  13. @gui = GUIManager.new()
  14. @display_properties = DisplayProperties.new()
  15. buttonpanel_rect = CL_Rect.new(CL_Point.new(0, 23), CL_Size.new(width, 33))
  16. selector_rect = CL_Rect.new(
  17. CL_Point.new(width - 134, buttonpanel_rect.bottom),
  18. CL_Size.new(134, height-buttonpanel_rect.bottom))
  19. minimap_rect = CL_Rect.new(CL_Point.new(3, height-53),
  20. CL_Size.new(width - selector_rect.get_width() - 4, 50))
  21. map_rect = CL_Rect.new(CL_Point.new(0, buttonpanel_rect.bottom),
  22. CL_Size.new(width - selector_rect.get_width() - 1,
  23. height - buttonpanel_rect.bottom -
  24. minimap_rect.get_height() - 3))
  25. @editor_map = EditorMapComponent.new(map_rect, @gui.get_component())
  26. @workspace = @editor_map.get_workspace()
  27. @workspace.set_tool(0, $tilemap_paint_tool.to_tool())
  28. @workspace.set_tool(2, $workspace_move_tool.to_tool())
  29. @workspace.set_tool(1, $tilemap_paint_tool.to_tool())
  30. # 'x' key
  31. @workspace.set_tool(120, $zoom_tool.to_tool())
  32. # 'u' key
  33. @workspace.set_tool(117, $objmap_select_tool.to_tool())
  34. @workspace.set_tool(106, $workspace_move_tool.to_tool())
  35. @workspace.set_tool(107, $zoom2_tool.to_tool())
  36. @workspace.set_tool(65507, $zoom2_tool.to_tool())
  37. @minimap = Minimap.new(@editor_map, minimap_rect, @gui.get_component())
  38. @selector_window = Panel.new(selector_rect, @gui.get_component())
  39. @tileselector = TileSelector.new(CL_Rect.new(CL_Point.new(3, 3),
  40. CL_Size.new(selector_rect.get_width() -3 ,
  41. selector_rect.get_height() - 3)), @selector_window)
  42. @tileselector.set_tileset($tileset)
  43. @tileselector.set_tiles($tileset.get_tiles())
  44. @objectselector = ObjectSelector.new(CL_Rect.new(CL_Point.new(3, 3),
  45. CL_Size.new(selector_rect.get_width()-3,
  46. selector_rect.get_height() - 3)),
  47. 42, 42, @selector_window)
  48. connect_v2_ObjectBrush_Point(@objectselector.sig_drop(), method(:on_object_drop))
  49. $game_objects.each { |objectdata|
  50. sprite = load_cl_sprite($datadir + objectdata[1])
  51. @objectselector.add_brush(ObjectBrush.new(sprite,
  52. make_metadata(objectdata)))
  53. }
  54. @worldmapobjectselector = ObjectSelector.new(CL_Rect.new(CL_Point.new(3, 3),
  55. CL_Size.new(selector_rect.get_width()-3,
  56. selector_rect.get_height() - 3)),
  57. 42, 42, @selector_window);
  58. connect_v2_ObjectBrush_Point(@worldmapobjectselector.sig_drop(),
  59. method(:on_worldmap_object_drop))
  60. $worldmap_objects.each { |object|
  61. @worldmapobjectselector.add_brush(ObjectBrush.new(
  62. make_sprite($datadir + object[1]),
  63. make_metadata(object[0])))
  64. }
  65. create_button_panel(buttonpanel_rect)
  66. @recent_files_menu = Menu.new(CL_Point.new(32*2, 54), @gui.get_component())
  67. @layer_menu = Menu.new(CL_Point.new(32*15+2, 54), @gui.get_component())
  68. @layer_menu.add_item($mysprite, "Show all", proc{ gui_show_all() })
  69. @layer_menu.add_item($mysprite, "Show current", proc{ gui_show_current() })
  70. @layer_menu.add_item($mysprite, "Show only current", proc{ gui_show_only_current() })
  71. # FIXME: Use ButtonPanel here instead
  72. @toolbar = Panel.new(CL_Rect.new(CL_Point.new(0, 23+33),
  73. CL_Size.new(33, 32*4+2)), @gui.get_component())
  74. @paint = Icon.new(CL_Rect.new(CL_Point.new(2, 32*0+2), CL_Size.new(32, 32)), make_sprite("../data/images/tools/stock-tool-pencil-22.png"), "Some tooltip", @toolbar);
  75. @paint.set_callback(proc{ set_tilemap_paint_tool() })
  76. @select = Icon.new(CL_Rect.new(CL_Point.new(2, 32*1+2), CL_Size.new(32,32)), make_sprite("../data/images/tools/stock-tool-rect-select-22.png"), "Some tooltip", @toolbar);
  77. @select.set_callback(proc{ set_tilemap_select_tool() })
  78. @zoom = Icon.new(CL_Rect.new(CL_Point.new(2, 32*2+2), CL_Size.new(32,32)), make_sprite("../data/images/tools/stock-tool-zoom-22.png"), "Some tooltip", @toolbar);
  79. @zoom.set_callback(proc{ set_zoom_tool() })
  80. @object = Icon.new(CL_Rect.new(CL_Point.new(2, 32*3+2), CL_Size.new(32,32)), make_sprite("../data/images/tools/stock-tool-clone-22.png"), "Some tooltip", @toolbar);
  81. @object.set_callback(proc{ set_objmap_select_tool() })
  82. # @stroke = Icon.new(CL_Rect.new(CL_Point.new(2, 32*4+2), CL_Size.new(32,32)), make_sprite("../data/images/tools/stock-tool-pencil-22.png"), "Some tooltip", @toolbar);
  83. # @stroke.set_callback(proc{ set_sketch_stroke_tool() })
  84. create_menu()
  85. @load_dialog = SimpleFileDialog.new("Load SuperTux Level", "Load", "Cancel", @gui.get_component())
  86. @load_dialog.set_filename($datadir + "levels/")
  87. @save_dialog = SimpleFileDialog.new("Save SuperTux Level as...", "Save", "Cancel", @gui.get_component())
  88. @save_dialog.set_filename($datadir + "levels/")
  89. register_keyboard_shortcuts()
  90. # Popup menu
  91. connect_v2($objmap_select_tool.sig_on_right_click(), proc{|x,y|
  92. puts "Launching Menu at #{x}, #{y}"
  93. menu = Menu.new(CL_Point.new(x, y), @gui.get_component())
  94. menu.add_item($mysprite, "Delete Object(s)", proc{
  95. puts "Trying to delete #{@workspace.get_map().get_metadata()} #{@workspace.get_map().get_metadata().objects}"
  96. cmd = ObjectDeleteCommand.new(@workspace.get_map().get_metadata().objects)
  97. $objmap_select_tool.get_selection().each { |i| cmd.add_object(i) }
  98. @workspace.get_map().execute(cmd.to_command())
  99. $objmap_select_tool.clear_selection()
  100. })
  101. menu.add_item($mysprite, "Edit Properties", proc{
  102. $objmap_select_tool.get_selection().each {|i|
  103. puts i
  104. puts i.get_data()
  105. i.get_data().property_dialog()
  106. }
  107. })
  108. menu.run()
  109. })
  110. end
  111. def register_keyboard_shortcuts()
  112. connect_v2(@editor_map.sig_on_key("f1"), proc{ |x, y| gui_toggle_minimap()})
  113. connect_v2(@editor_map.sig_on_key("m"), proc{ |x, y| gui_toggle_minimap()})
  114. connect_v2(@editor_map.sig_on_key("g"), proc{ |x, y| gui_toggle_grid()})
  115. connect_v2(@editor_map.sig_on_key("4"), proc{ |x, y| gui_toggle_display_props()})
  116. connect_v2(@editor_map.sig_on_key("3"), proc{ |x, y| gui_show_foreground()})
  117. connect_v2(@editor_map.sig_on_key("2"), proc{ |x, y| gui_show_interactive()})
  118. connect_v2(@editor_map.sig_on_key("1"), proc{ |x, y| gui_show_background()})
  119. connect_v2(@editor_map.sig_on_key("5"), proc{ |x, y| @editor_map.zoom_in(CL_Point.new(x, y))})
  120. connect_v2(@editor_map.sig_on_key("6"), proc{ |x, y| @editor_map.zoom_out(CL_Point.new(x, y))})
  121. connect_v2(@editor_map.sig_on_key("i"), proc{ |x, y| insert_path_node(x,y)})
  122. connect_v2(@editor_map.sig_on_key("c"), proc{ |x, y| connect_path_nodes()})
  123. connect_v2(@editor_map.sig_on_key("7"), proc{ |x, y| @workspace.get_map().get_metadata().parent.activate_sector("main", @workspace)})
  124. connect_v2(@editor_map.sig_on_key("8"), proc{ |x, y| @workspace.get_map().get_metadata().parent.activate_sector("another_world", @workspace)})
  125. connect_v2(@editor_map.sig_on_key("e"), proc{ |x, y| gui_show_object_properties()})
  126. connect_v2(@editor_map.sig_on_key("a"), proc { |x, y|
  127. pos = @editor_map.screen2world(CL_Point.new(x, y))
  128. rectobj = ObjMapRectObject.new(CL_Rect.new(pos,
  129. CL_Size.new(128, 64)),
  130. CL_Color.new(0, 255, 255, 155),
  131. make_metadata(nil))
  132. # rectobj.set_metadata(metadata)
  133. @workspace.get_map().get_metadata().objects.add_object(rectobj.to_object())
  134. })
  135. end
  136. def create_menu()
  137. @menu = CL_Menu.new(@gui.get_component())
  138. @menu.add_item("File/New...", method(:gui_level_new))
  139. @menu.add_item("File/Open...", method(:gui_level_load))
  140. @menu.add_item("File/Save...", method(:gui_level_save))
  141. # @menu.add_item("File/Save Commands...", menu_file_save_commands)
  142. # @menu.add_item("File/Save As...", method(:gui_level_save_as))
  143. @menu.add_item("File/Properties...", method(:gui_edit_level))
  144. @menu.add_item("File/Quit", proc{ @gui.quit })
  145. @menu.add_item("Edit/Smooth Selection", method(:gui_smooth_level_struct))
  146. @menu.add_item("Edit/Resize", method(:gui_resize_level))
  147. @menu.add_item("Edit/Resize to selection", method(:gui_resize_level_to_selection))
  148. @menu.add_item("Zoom/1:4 (25%) ", proc{ self.gui_set_zoom(0.25) })
  149. @menu.add_item("Zoom/1:2 (50%) ", proc{ self.gui_set_zoom(0.5) })
  150. @menu.add_item("Zoom/1:1 (100%) ", proc{ self.gui_set_zoom(1.0) })
  151. @menu.add_item("Zoom/2:1 (200%) ", proc{ self.gui_set_zoom(2.0) })
  152. @menu.add_item("Zoom/4:1 (400%) ", proc{ self.gui_set_zoom(4.0) })
  153. end
  154. def create_button_panel(rect)
  155. button_panel = ButtonPanel.new(rect.left, rect.top,
  156. rect.get_width(), rect.get_height(), true, @gui.get_component)
  157. # File Handling
  158. button_panel.add_icon("../data/images/icons24/stock_new.png", proc{ self.gui_level_new() })
  159. button_panel.add_icon("../data/images/icons24/stock_open.png", proc{ self.gui_level_load() })
  160. button_panel.add_small_icon("../data/images/icons24/downarrow.png", proc{ @recent_files_menu.run() })
  161. button_panel.add_icon("../data/images/icons24/stock_save.png", proc{ self.gui_level_save() })
  162. button_panel.add_icon("../data/images/icons24/stock_save_as.png", proc{ self.gui_level_save_as() })
  163. # Copy&Paste
  164. button_panel.add_separator()
  165. button_panel.add_icon("../data/images/icons24/stock_copy.png")
  166. button_panel.add_icon("../data/images/icons24/stock_paste.png")
  167. # Undo Redo
  168. button_panel.add_separator()
  169. @undo_icon = button_panel.add_icon("../data/images/icons24/stock_undo.png",
  170. proc{ @workspace.get_map().undo() })
  171. @redo_icon = button_panel.add_icon("../data/images/icons24/stock_redo.png",
  172. proc{ @workspace.get_map().redo() })
  173. @undo_icon.disable()
  174. @redo_icon.disable()
  175. # Visibility Toggles
  176. button_panel.add_separator()
  177. @minimap_icon = button_panel.add_icon("../data/images/icons24/minimap.png", proc{ gui_toggle_minimap() })
  178. @grid_icon = button_panel.add_icon("../data/images/icons24/grid.png", proc{ gui_toggle_grid() })
  179. # Layers
  180. button_panel.add_separator()
  181. @background_icon = button_panel.add_icon("../data/images/icons24/background.png", proc{ gui_show_background() })
  182. @interactive_icon = button_panel.add_icon("../data/images/icons24/interactive.png", proc{ gui_show_interactive() })
  183. @foreground_icon = button_panel.add_icon("../data/images/icons24/foreground.png", proc{ gui_show_foreground() })
  184. @eye_icon = button_panel.add_icon("../data/images/icons24/eye.png", proc{ @layer_menu.run() })
  185. button_panel.add_separator()
  186. @sector_icon = button_panel.add_icon("../data/images/icons24/sector.png", proc{ gui_switch_sector_menu() })
  187. button_panel.add_separator()
  188. @run_icon = button_panel.add_icon("../data/images/icons24/run.png", proc{ gui_run_level() })
  189. @tilegroup_icon = button_panel.add_icon("../data/images/icons24/eye.png", proc{ @tilegroup_menu.run() })
  190. @tilegroup_menu = Menu.new(CL_Point.new(@tilegroup_icon.get_screen_x(),
  191. @tilegroup_icon.get_screen_y() + @tilegroup_icon.get_height() - 2),
  192. @gui.get_component())
  193. @tilegroup_menu.add_item($mysprite, "All Tiles", proc{@tileselector.set_tiles($tileset.get_tiles())})
  194. $tileset.tilegroups.each { |tilegroup|
  195. @tilegroup_menu.add_item($mysprite, tilegroup.name, proc{@tileselector.set_tiles(tilegroup.tiles)})
  196. }
  197. end
  198. def on_worldmap_object_drop(brush, pos)
  199. pos = @editor_map.screen2world(pos)
  200. object_type = get_ruby_object(brush.get_data())
  201. create_worldmapobject_at_pos(
  202. $gui.workspace.get_map().get_metadata().objects, object_type, pos)
  203. end
  204. def on_object_drop(brush, pos)
  205. pos = @editor_map.screen2world(pos)
  206. data = get_ruby_object(brush.get_data())
  207. create_gameobject($gui.workspace.get_map(), $gui.workspace.get_map().get_metadata().objects, data, pos)
  208. end
  209. def run()
  210. @gui.run()
  211. end
  212. # def show_colorpicker()
  213. # @tileselector.show(false)
  214. # @objectselector.show(false)
  215. # @worldmapobjectselector.show(false)
  216. # # @colorpicker.show(true)
  217. # end
  218. def show_objects()
  219. @tileselector.show(false)
  220. if $use_worldmap
  221. @worldmapobjectselector.show(true)
  222. @objectselector.show(false)
  223. else
  224. @worldmapobjectselector.show(false)
  225. @objectselector.show(true)
  226. end
  227. # @colorpicker.show(false)
  228. end
  229. def show_tiles()
  230. @tileselector.show(true)
  231. @objectselector.show(false)
  232. @worldmapobjectselector.show(false)
  233. # @colorpicker.show(false)
  234. end
  235. def show_none()
  236. @tileselector.show(false)
  237. @objectselector.show(false)
  238. @worldmapobjectselector.show(false)
  239. # @colorpicker.show(false)
  240. end
  241. def set_tilemap_paint_tool()
  242. @workspace.set_tool(0, $tilemap_paint_tool.to_tool())
  243. @workspace.set_tool(1, $tilemap_paint_tool.to_tool())
  244. @paint.set_down()
  245. @select.set_up()
  246. @zoom.set_up()
  247. @object.set_up()
  248. show_tiles()
  249. end
  250. def set_tilemap_select_tool()
  251. @workspace.set_tool(0, $tilemap_select_tool.to_tool())
  252. @paint.set_up()
  253. @select.set_down()
  254. @zoom.set_up()
  255. @object.set_up()
  256. show_none()
  257. end
  258. def set_zoom_tool()
  259. @workspace.set_tool(0, $zoom_tool.to_tool())
  260. @paint.set_up()
  261. @select.set_up()
  262. @zoom.set_down()
  263. @object.set_up()
  264. show_none()
  265. end
  266. # def set_sketch_stroke_tool()
  267. # @workspace.set_tool(0, $sketch_stroke_tool.to_tool())
  268. # @paint.set_up()
  269. # @select.set_up()
  270. # @zoom.set_up()
  271. # @object.set_down()
  272. # show_colorpicker()
  273. # end
  274. def set_objmap_select_tool()
  275. @workspace.set_tool(0, $objmap_select_tool.to_tool())
  276. @paint.set_up()
  277. @select.set_up()
  278. @zoom.set_up()
  279. @object.set_down()
  280. show_objects()
  281. end
  282. def gui_show_foreground()
  283. @display_properties.layer = FOREGROUND_LAYER
  284. @display_properties.set(@workspace.get_map().get_metadata())
  285. TilemapLayer.set_current(@workspace.get_map().get_metadata().foreground)
  286. @foreground_icon.set_down()
  287. @interactive_icon.set_up()
  288. @background_icon.set_up()
  289. @minimap.update_minimap()
  290. end
  291. def gui_show_background()
  292. @display_properties.layer = BACKGROUND_LAYER
  293. @display_properties.set(@workspace.get_map().get_metadata())
  294. TilemapLayer.set_current(@workspace.get_map().get_metadata().background)
  295. @foreground_icon.set_up()
  296. @interactive_icon.set_up()
  297. @background_icon.set_down()
  298. @minimap.update_minimap()
  299. end
  300. def gui_show_interactive()
  301. @display_properties.layer = INTERACTIVE_LAYER
  302. @display_properties.set(@workspace.get_map().get_metadata())
  303. TilemapLayer.set_current(@workspace.get_map().get_metadata().interactive)
  304. @foreground_icon.set_up()
  305. @interactive_icon.set_down()
  306. @background_icon.set_up()
  307. @minimap.update_minimap()
  308. end
  309. def gui_show_all()
  310. @display_properties.show_all = true
  311. @display_properties.current_only = false
  312. @display_properties.set(@workspace.get_map().get_metadata())
  313. end
  314. def gui_show_current()
  315. @display_properties.show_all = false
  316. @display_properties.current_only = false
  317. @display_properties.set(@workspace.get_map().get_metadata())
  318. end
  319. def gui_show_only_current()
  320. @display_properties.show_all = false
  321. @display_properties.current_only = true
  322. @display_properties.set(@workspace.get_map().get_metadata())
  323. end
  324. def gui_toggle_minimap()
  325. if @minimap.is_visible() then
  326. @minimap.show(false)
  327. @minimap_icon.set_up()
  328. else
  329. @minimap.show(true)
  330. @minimap_icon.set_down()
  331. end
  332. end
  333. def gui_toggle_grid()
  334. tilemap = @workspace.get_map().get_metadata().foreground;
  335. tilemap.set_draw_grid(!tilemap.get_draw_grid())
  336. if tilemap.get_draw_grid()
  337. @grid_icon.set_down()
  338. else
  339. @grid_icon.set_up()
  340. end
  341. end
  342. def gui_toggle_display_props()
  343. if @display_properties.show_all
  344. @display_properties.show_all = false
  345. elsif not(@display_properties.current_only)
  346. @display_properties.current_only = true
  347. else
  348. @display_properties.show_all = true
  349. @display_properties.current_only = false
  350. end
  351. @display_properties.set(@workspace.get_map().get_metadata())
  352. end
  353. def gui_run_level()
  354. puts "Run this level..."
  355. if $use_worldmap
  356. tmpfile = "/tmp/tmpflexlay-worldmap.stwm"
  357. supertux_save_level(tmpfile)
  358. else
  359. # FIXME: use real tmpfile
  360. tmpfile = "/tmp/tmpflexlay-supertux.stl"
  361. supertux_save_level(tmpfile)
  362. end
  363. fork { exec("#{$datadir}/../supertux", tmpfile) }
  364. end
  365. def gui_resize_level()
  366. level = @workspace.get_map().get_metadata()
  367. dialog = GenericDialog.new("Resize Level", @gui.get_component())
  368. dialog.add_int("Width: ", level.width)
  369. dialog.add_int("Height: ", level.height)
  370. dialog.add_int("X: ", 0)
  371. dialog.add_int("Y: ", 0)
  372. dialog.set_callback(proc{|w, h, x, y|
  373. level.resize(CL_Size.new(w, h), CL_Point.new(x, y))})
  374. end
  375. def gui_smooth_level_struct()
  376. puts "Smoothing level structure"
  377. tilemap = TilemapLayer.current()
  378. data = tilemap.get_data()
  379. width = tilemap.get_width()
  380. height = tilemap.get_height()
  381. get = proc { |x, y| return data[y*width + x] }
  382. set = proc { |x, y, val| data[y*width + x] = val }
  383. smooth = proc do |x, y|
  384. $itile_conditions.each do |ary|
  385. if (($solid_itiles.index(get[x-1,y-1]) ? 1 : 0) == ary[0] \
  386. and ($solid_itiles.index(get[x, y-1]) ? 1 : 0) == ary[1] \
  387. and ($solid_itiles.index(get[x+1,y-1]) ? 1 : 0) == ary[2] \
  388. and ($solid_itiles.index(get[x-1,y ]) ? 1 : 0) == ary[3] \
  389. and ($solid_itiles.index(get[x, y ]) ? 1 : 0) == ary[4] \
  390. and ($solid_itiles.index(get[x+1,y ]) ? 1 : 0) == ary[5] \
  391. and ($solid_itiles.index(get[x-1,y+1]) ? 1 : 0) == ary[6] \
  392. and ($solid_itiles.index(get[x, y+1]) ? 1 : 0) == ary[7] \
  393. and ($solid_itiles.index(get[x+1,y+1]) ? 1 : 0) == ary[8])
  394. then
  395. set[x,y, ary[9]]
  396. end
  397. end
  398. end
  399. rect = $tilemap_select_tool.get_selection_rect()
  400. start_x = rect.left
  401. end_x = rect.right
  402. start_y = rect.top
  403. end_y = rect.bottom
  404. for y in (start_y..end_y) do
  405. for x in (start_x..end_x) do
  406. smooth[x,y]
  407. end
  408. end
  409. tilemap.set_data(data)
  410. end
  411. def gui_resize_level_to_selection()
  412. level = @workspace.get_map().get_metadata()
  413. rect = $tilemap_select_tool.get_selection_rect()
  414. if (rect.get_width() > 2 and rect.get_height() > 2)
  415. level.resize(rect.get_size(), CL_Point.new(-rect.left, -rect.top))
  416. end
  417. end
  418. def gui_edit_level()
  419. level = @workspace.get_map().get_metadata().get_level()
  420. dialog = GenericDialog.new("Edit Level", @gui.get_component())
  421. dialog.add_string("Name:", level.name)
  422. dialog.add_string("Author:", level.author)
  423. dialog.add_int("Time:", level.time)
  424. dialog.set_block() { |name, author, time|
  425. level.name = name
  426. level.author = author
  427. level.time = time
  428. }
  429. end
  430. def gui_edit_sector()
  431. level = @workspace.get_map().get_metadata().get_level()
  432. dialog = GenericDialog.new("Edit Sector", @gui.get_component())
  433. dialog.add_string("Name: ", level.current_sector.name)
  434. dialog.add_string("Music: ", level.current_sector.music)
  435. dialog.add_float("Gravity: ", level.current_sector.gravity)
  436. dialog.set_block() { |name, music, gravity|
  437. level.current_sector.name = name
  438. level.current_sector.music = music
  439. level.current_sector.gravity = gravity
  440. }
  441. end
  442. def gui_set_zoom(zoom)
  443. gc = @editor_map.get_gc_state()
  444. pos = gc.get_pos()
  445. gc.set_zoom(zoom)
  446. gc.set_pos(pos)
  447. end
  448. def gui_remove_sector()
  449. sector = @workspace.get_map().get_metadata()
  450. sector.get_level().remove_sector(sector.name)
  451. end
  452. def gui_add_sector()
  453. level = @workspace.get_map().get_metadata().get_level()
  454. name = "sector"
  455. uniq_name = name
  456. i = 2
  457. while level.get_sectors().index(uniq_name)
  458. uniq_name = name + "<%d>" % i
  459. i += 1
  460. end
  461. sector = Sector.new(level)
  462. sector.new_from_size(uniq_name, 30, 20);
  463. level.add_sector(sector)
  464. level.activate_sector(uniq_name, @workspace)
  465. gui_edit_sector();
  466. end
  467. def gui_switch_sector_menu()
  468. mymenu = Menu.new(CL_Point.new(530, 54), @gui.get_component())
  469. sector = @workspace.get_map().get_metadata()
  470. sector.parent.get_sectors().each { |i|
  471. if sector.name == i then
  472. current = " [current]"
  473. else
  474. current = ""
  475. end
  476. mymenu.add_item($mysprite, ("Sector (%s)%s" % [i, current]), proc {
  477. print "Switching to %s\n" % i
  478. @workspace.get_map().get_metadata().parent.activate_sector(i, @workspace)
  479. })
  480. }
  481. mymenu.add_separator()
  482. mymenu.add_item($mysprite, "Create New Sector", proc {
  483. gui_add_sector()
  484. })
  485. mymenu.add_item($mysprite, "Remove Current Sector", proc {
  486. gui_remove_sector()
  487. })
  488. mymenu.add_item($mysprite, "Edit Sector Properties", proc {
  489. gui_edit_sector()
  490. })
  491. mymenu.run()
  492. end
  493. def gui_show_object_properties()
  494. $objmap_select_tool.get_selection()
  495. selection = $objmap_select_tool.get_selection()
  496. if selection.length() > 1 then
  497. print "Warning: Selection to large"
  498. elsif selection.length() == 1 then
  499. obj = selection[0].get_data()
  500. puts obj
  501. obj.property_dialog()
  502. else
  503. print "Warning: Selection is empty\n"
  504. end
  505. end
  506. def on_map_change()
  507. if (@workspace.get_map().undo_stack_size() > 0)
  508. @undo_icon.enable()
  509. else
  510. @undo_icon.disable()
  511. end
  512. if (@workspace.get_map().redo_stack_size() > 0)
  513. @redo_icon.enable()
  514. else
  515. @redo_icon.disable()
  516. end
  517. end
  518. def gui_level_save_as()
  519. filename = @save_dialog.get_filename()
  520. if filename[-1] == "/"[0]
  521. @save_dialog.set_filename(filename)
  522. else
  523. @save_dialog.set_filename(File.dirname(filename) + "/")
  524. end
  525. @save_dialog.run(proc{|filename| supertux_save_level(filename) })
  526. end
  527. def gui_level_save()
  528. if $use_worldmap
  529. filename = @workspace.get_map().get_metadata().filename
  530. else
  531. filename = @workspace.get_map().get_metadata().parent.filename
  532. end
  533. print "Filename: ", filename, "\n"
  534. if filename
  535. @save_dialog.set_filename(filename)
  536. else
  537. filename = @save_dialog.get_filename()
  538. if filename[-1] == "/"[0]
  539. @save_dialog.set_filename(filename)
  540. else
  541. @save_dialog.set_filename(File.dirname(filename) + "/")
  542. end
  543. end
  544. @save_dialog.run(proc{|filename| supertux_save_level(filename) })
  545. end
  546. def gui_level_new()
  547. puts "not implemented: gui_level_new()"
  548. end
  549. def gui_level_load()
  550. @load_dialog.run(proc{|filename| supertux_load_level(filename) })
  551. end
  552. def insert_path_node(x,y)
  553. print "Insert path Node"
  554. m = @workspace.get_map().get_metadata()
  555. pathnode = ObjMapPathNode.new(@editor_map.screen2world(CL_Point.new(x, y)),
  556. make_metadata("PathNode"))
  557. pathnode.to_object().set_metadata(make_metadata(PathNode.new(pathnode)))
  558. m.objects.add_object(pathnode.to_object())
  559. end
  560. def connect_path_nodes()
  561. print "Connecting path nodes"
  562. pathnodes = []
  563. for i in $objmap_select_tool.get_selection()
  564. obj = i.get_data()
  565. if obj.is_a?(PathNode)
  566. pathnodes.push(obj.node)
  567. end
  568. end
  569. last = nil
  570. for i in pathnodes
  571. if last != nil
  572. last.connect(i)
  573. end
  574. last = i
  575. end
  576. end
  577. end
  578. class DisplayProperties
  579. attr_reader :layer, :show_all, :current_only
  580. attr_writer :layer, :show_all, :current_only
  581. def initialize()
  582. @layer = INTERACTIVE_LAYER
  583. @show_all = false
  584. @current_only = false
  585. end
  586. def set(map)
  587. if map == nil || !map.instance_of?(Sector)
  588. return
  589. end
  590. if @current_only
  591. active = CL_Color.new(255, 255, 255)
  592. deactive = CL_Color.new(0, 0, 0, 10)
  593. else
  594. active = CL_Color.new(255, 255, 255)
  595. deactive = CL_Color.new(150, 150, 250, 150)
  596. end
  597. if (@show_all)
  598. map.foreground.set_foreground_color(active)
  599. map.interactive.set_foreground_color(active)
  600. map.background.set_foreground_color(active)
  601. else
  602. if (@layer == FOREGROUND_LAYER)
  603. map.foreground.set_foreground_color(active)
  604. else
  605. map.foreground.set_foreground_color(deactive)
  606. end
  607. if (@layer == INTERACTIVE_LAYER)
  608. map.interactive.set_foreground_color(active)
  609. else
  610. map.interactive.set_foreground_color(deactive)
  611. end
  612. if (@layer == BACKGROUND_LAYER)
  613. map.background.set_foreground_color(active)
  614. else
  615. map.background.set_foreground_color(deactive)
  616. end
  617. end
  618. end
  619. end
  620. def supertux_load_level(filename)
  621. if filename.scan(/.stwm$/) != []
  622. supertux_load_worldmap(filename)
  623. return
  624. end
  625. print "Loading: ", filename, "\n"
  626. level = Level.new(filename)
  627. level.activate($gui.workspace)
  628. if not($recent_files.find{|el| el == filename}) then
  629. $recent_files.push(filename)
  630. $gui.recent_files_menu.add_item($mysprite, filename,
  631. proc { supertux_load_level(filename) })
  632. end
  633. $gui.minimap.update_minimap()
  634. end
  635. def supertux_load_worldmap(filename)
  636. print "Loading: ", filename, "\n"
  637. worldmap = WorldMap.new(filename)
  638. worldmap.activate($gui.workspace)
  639. if not($recent_files.find{|el| el == filename}) then
  640. $recent_files.push(filename)
  641. $gui.recent_files_menu.add_item($mysprite, filename,
  642. proc { supertux_load_worldmap(filename) })
  643. end
  644. $gui.minimap.update_minimap()
  645. $use_worldmap = true
  646. end
  647. def supertux_save_level(filename)
  648. if $use_worldmap
  649. level = $gui.workspace.get_map().get_metadata()
  650. else
  651. level = $gui.workspace.get_map().get_metadata().parent
  652. end
  653. # Do backup save
  654. if File.exists?(filename) then
  655. File.rename(filename, filename + "~")
  656. end
  657. level.save(filename)
  658. level.filename = filename
  659. end
  660. # EOF #