A bunch of changes I apparently didn't add into afd809d1e9

This commit is contained in:
2014-05-26 16:28:22 -07:00
parent 63875903eb
commit ba5b671730
8 changed files with 302 additions and 63 deletions

View File

@@ -1,16 +1,20 @@
require 'singleton' require 'singleton'
module Tailor module Tailor
module Collection class Collection
include Singleton include Singleton
attr_accessor :library attr_accessor :library
def initialize def initialize
clear
end
def clear
@metadata = { @metadata = {
"author": "", "author" => "",
"name": "", "name" => "",
"license": "" "license" => ""
} }
self.library = Tailor::Library.new self.library = Tailor::Library.new
@pages = {} @pages = {}
@@ -18,23 +22,23 @@ module Tailor
def to_json def to_json
js = { js = {
"metadata" => metadata, "metadata" => @metadata,
"library" => {}, "library" => {},
"pages" => {} "pages" => {}
} }
@library.each do |tileset| @library.each do |tileset|
js['library'][tileset['name']] = tileset.get_filename js['library'][tileset.tileset_name] = tileset.get_filename
end end
@pages.each do |page| @pages.each do |page|
js['pages'][page.page_name] = page.to_json js['pages'][page.page_name] = page.to_json
end end
js
end end
def save_json(filename) def save_json(filename)
dname = File.dirname(filename) dname = File.dirname(filename)
Dir.mkdir(dname) unless Dir.exist?(dname) Dir.mkdir(dname) unless Dir.exist?(dname)
File.open(filename, "w") do |file| File.open(filename, "w") do |file|
file.write(JSON.pretty_generate(to_json)) file.write(JSON.pretty_generate(to_json))
end end
@@ -51,13 +55,12 @@ module Tailor
end end
def load_json(filename) def load_json(filename)
dname = File.dirname(filename) clear
Dir.mkdir(dname) unless Dir.exist?(dname)
File.open(filename, "r") do |file| File.open(filename, "r") do |file|
js = JSON.parse(file.read) js = JSON.parse(file.read)
end
from_json(js) from_json(js)
end end
end
end end
end end

View File

@@ -1,5 +1,6 @@
require 'wx' require 'wx'
require 'tailor/GUI/MainWindow' require 'tailor/GUI/MainWindow'
require 'tailor/Library'
module Tailor module Tailor
module GUI module GUI

View File

@@ -19,7 +19,7 @@ module Tailor
end end
class GridDisplay < Tailor::GUI::BitmapDisplay class GridDisplay < Wx::ScrolledWindow
attr_accessor :tileset attr_accessor :tileset
@@ -36,9 +36,16 @@ module Tailor
evt_left_up() { |event| on_gridClicked(event) } evt_left_up() { |event| on_gridClicked(event) }
end end
def set_tileset(tileset)
self.tileset = tileset
@bitmap = tileset.image.convert_to_bitmap
refresh_grid
end
def set_image(image) def set_image(image)
self.tileset.image = image self.tileset.image = image
@bitmap = image.convert_to_bitmap @bitmap = image.convert_to_bitmap
set_scrollbars(1, 1, @bitmap.width, @bitmap.height)
refresh_grid refresh_grid
end end

View File

@@ -1,12 +1,13 @@
require 'wx' require 'wx'
require 'Tailor/Library' require 'Tailor/Collection'
module Tailor module Tailor
module GUI module GUI
class LibraryManager class LibraryManager < Wx::Frame
def initialize(*args) def initialize(*args)
super(*args) super(*args)
@library = Tailor::Library.instance @library = Tailor::Collection.instance.library
@tileset = nil
@panel = Wx::Panel.new(self) @panel = Wx::Panel.new(self)
@sizer = Wx::BoxSizer.new(Wx::VERTICAL) @sizer = Wx::BoxSizer.new(Wx::VERTICAL)
@@ -19,12 +20,86 @@ module Tailor
@library.tileset_names, @library.tileset_names,
Wx::LB_SORT | Wx::LB_SINGLE) Wx::LB_SORT | Wx::LB_SINGLE)
vertSizer.add(@tilesetList, 0, flags = Wx::EXPAND|Wx::ALL) vertSizer.add(@tilesetList, 0, flags = Wx::EXPAND|Wx::ALL)
@addBtn = Wx::Button.new(@panel, Wx::ID_ANY, "Add Tileset")
evt_button(@addBtn.get_id()) { |event| on_AddClicked(event) }
@removeBtn = Wx::Button.new(@panel, Wx::ID_ANY, "Remove Tileset")
evt_button(@removeBtn.get_id()) { |event| on_RemoveClicked(event) }
vertSizer.add(@addBtn, 1, flags = Wx::GROW)
vertSizer.add(@removeBtn, 1, flags = Wx::GROW)
horizSizer.add(vertSizer, 0, flags = Wx::EXPAND|Wx::ALL) horizSizer.add(vertSizer, 0, flags = Wx::EXPAND|Wx::ALL)
@previewPane = Tailor::GUI::GridDisplay.new(@panel,
Wx::ID_ANY,
Wx::DEFAULT_POSITION,
Wx::DEFAULT_SIZE,
Wx::VSCROLL | Wx::HSCROLL | Wx::ALWAYS_SHOW_SB)
@previewPane.set_min_size(Wx::Size.new(320, 240))
horizSizer.add(@previewPane, 1, flags=Wx::EXPAND|Wx::ALL)
@sizer.add(horizSizer, 1, flag=Wx::EXPAND|Wx::ALL) @sizer.add(horizSizer, 1, flag=Wx::EXPAND|Wx::ALL)
@panel.set_sizer(@sizer) @panel.set_sizer(@sizer)
@sizer.set_size_hints(self) @sizer.set_size_hints(self)
evt_listbox(@tilesetList) { |event| on_ListClicked(event) }
evt_listbox_dclick(@tilesetList) { |event| on_ListDoubleClicked(event) }
if @tilesetList.get_count > 0
@tilesetList.set_selection(0)
on_ListClicked(nil)
end
show() show()
end end
def on_AddClicked(event)
wildcards = "*.json"
fd = Wx::FileDialog.new(self, "Select tileset to load",
:wildcard => wildcards,
:style => Wx::FD_FILE_MUST_EXIST)
if fd.show_modal == Wx::ID_OK
@tileset = @library.load_tileset(fd.get_path)
idx = @tilesetList.append(@tileset.tileset_name)
@tilesetList.set_selection(idx)
refresh_image
end
refresh
end
def on_RemoveClicked(event)
idx = @tilesetList.get_selection
name = @tilesetList.get_string_selection
@library.delete(name)
@tilesetList.deselect(idx)
@tilesetList.delete(idx)
if @tilesetList.get_count > 0
@tilesetList.set_selection(0)
on_ListClicked(nil)
else
@previewPane.hide
end
end
def on_ListDoubleClicked(event)
@tileset = @library.by_name(@tilesetList.get_string_selection)
editor = Tailor::GUI::TilesetEditor.new(self, Wx::ID_ANY)
editor.set_tileset(@tileset)
editor.disable_load
editor.disable_import
editor.show
if (editor.has_saved and (not editor.has_loaded))
on_RemoveClicked
idx = @tilesetList.append(@tileset.tileset_name)
@tilesetList.set_selection(idx)
on_ListClicked
end
end
def on_ListClicked(event)
@tileset = @library.by_name(@tilesetList.get_string_selection)
refresh_image
end
def refresh_image
@previewPane.set_tileset(@tileset)
@previewPane.show
end
end end
end end
end end

View File

@@ -1,48 +1,62 @@
require 'wx' require 'wx'
require 'Tailor/version' require 'Tailor/version'
require 'Tailor/Collection'
require 'Tailor/GUI/TilesetProperties' require 'Tailor/GUI/TilesetProperties'
require 'tailor/GUI/TilesetEditor' require 'tailor/GUI/TilesetEditor'
require 'tailor/GUI/LibraryManager'
module Tailor module Tailor
module GUI module GUI
class MainWindow < Wx::Frame class MainWindow < Wx::Frame
def initialize() def initialize()
super(nil, -1, 'Tailor') super(nil, -1, 'Tailor')
@collection = Tailor::Collection.instance
@mainPanel = nil
init_menubar() init_menubar()
show() show()
end end
def init_menubar def init_menubar
@menuBar = Wx::MenuBar.new @menuBar = Wx::MenuBar.new
menuFile = Wx::Menu.new @menuFile = Wx::Menu.new
menuFileNew = menuFile.append(Wx::ID_ANY, "&New\tAlt-N", "New Compilation") menuFileNew = @menuFile.append(Wx::ID_ANY, "&New\tAlt-N", "New Compilation")
menuFileOpen = menuFile.append(Wx::ID_ANY, "&Open\tAlt-O", "Open Compilation") menuFileOpen = @menuFile.append(Wx::ID_ANY, "&Open\tAlt-O", "Open Compilation")
menuFileSave = menuFile.append(Wx::ID_ANY, "&Save\tAlt-S", "Save Compilation") @menuFileSave = @menuFile.append(Wx::ID_ANY, "&Save\tAlt-S", "Save Compilation")
menuFileExport = menuFile.append(Wx::ID_ANY, "&Export\tAlt-E", "Export Compilation") @menuFileSaveAs = @menuFile.append(Wx::ID_ANY, "Save As", "Save Compilation As...")
menuFile.append_separator @menuFileExport = @menuFile.append(Wx::ID_ANY, "&Export\tAlt-E", "Export Compilation")
menuFileClose = menuFile.append(Wx::ID_ANY, "&Close\tAlt-W", "Close Compilation") @menuFile.append_separator
menuFile.append_separator @menuFileClose = @menuFile.append(Wx::ID_ANY, "&Close\tAlt-W", "Close Compilation")
menuFileExit = menuFile.append(Wx::ID_EXIT, "E&xit\tAlt-X", "Exit Tailor") @menuFile.append_separator
@menuBar.append(menuFile, "&File") menuFileExit = @menuFile.append(Wx::ID_EXIT, "E&xit\tAlt-X", "Exit Tailor")
menuEdit = Wx::Menu.new @menuBar.append(@menuFile, "&File")
menuEditTileset = menuEdit.append(Wx::ID_ANY, "&Tileset\tAlt-T", "Edit Tileset") @menuLibrary = Wx::Menu.new
@menuBar.append(menuEdit, "&Edit") @menuLibraryManager = @menuLibrary.append(Wx::ID_ANY, "&Manage\tAlt-M", "Library Manager")
menuLibraryTileset = @menuLibrary.append(Wx::ID_ANY, "&Tileset Editor\tAlt-T", "Tileset Editor")
@menuBar.append(@menuLibrary, "&Library")
menuHelp = Wx::Menu.new menuHelp = Wx::Menu.new
menuHelpAbout = menuHelp.append(Wx::ID_ABOUT, "&About...\tF1", "About Tailor") menuHelpAbout = menuHelp.append(Wx::ID_ABOUT, "&About...\tF1", "About Tailor")
@menuBar.append(menuHelp, "&Help") @menuBar.append(menuHelp, "&Help")
self.menu_bar = @menuBar self.menu_bar = @menuBar
evt_menu(menuFileNew, :on_file_new) evt_menu(menuFileNew, :on_file_new)
evt_menu(menuEditTileset, :on_edit_tileset) evt_menu(menuLibraryTileset, :on_library_tileset)
evt_menu(@menuLibraryManager, :on_library_manager)
evt_menu(menuFileOpen, :on_file_open) evt_menu(menuFileOpen, :on_file_open)
evt_menu(menuFileSave, :on_file_save) evt_menu(@menuFileSave, :on_file_save)
evt_menu(menuFileExport, :on_file_export) evt_menu(@menuFileSaveAs, :on_file_saveas)
evt_menu(menuFileClose, :on_file_close) evt_menu(@menuFileExport, :on_file_export)
evt_menu(@menuFileClose, :on_file_close)
evt_menu(Wx::ID_EXIT, :on_file_exit) evt_menu(Wx::ID_EXIT, :on_file_exit)
evt_menu(Wx::ID_ABOUT, :on_help_about) evt_menu(Wx::ID_ABOUT, :on_help_about)
@menuFile.enable(@menuFileSave.get_id, false)
@menuFile.enable(@menuFileSaveAs.get_id, false)
@menuFile.enable(@menuFileExport.get_id, false)
@menuFile.enable(@menuFileClose.get_id, false)
@menuLibrary.enable(@menuLibraryManager.get_id, false)
end end
def on_file_new def refresh_project
@mainPanel = Wx::Panel.new(self) @mainPanel = Wx::Panel.new(self)
@mainPanelSizer = Wx::BoxSizer.new(Wx::HORIZONTAL) @mainPanelSizer = Wx::BoxSizer.new(Wx::HORIZONTAL)
@mainPanel.set_sizer(@mainPanelSizer) @mainPanel.set_sizer(@mainPanelSizer)
@@ -53,27 +67,84 @@ module Tailor
@mainPanelSizer.add(button, 0, Wx::EXPAND|Wx::ALL, 2) @mainPanelSizer.add(button, 0, Wx::EXPAND|Wx::ALL, 2)
@mainPanelSizer.set_size_hints(@mainPanel) @mainPanelSizer.set_size_hints(@mainPanel)
@mainPanelSizer.set_size_hints(self) @mainPanelSizer.set_size_hints(self)
@menuFile.enable(@menuFileSave.get_id, true)
@menuFile.enable(@menuFileSaveAs.get_id, true)
@menuFile.enable(@menuFileExport.get_id, true)
@menuFile.enable(@menuFileClose.get_id, true)
@menuLibrary.enable(@menuLibraryManager.get_id, true)
end
def on_file_new
wildcards = "*.json"
fd = Wx::FileDialog.new(self, "Select location for new collection",
:wildcard => wildcards,
:style => Wx::FD_OVERWRITE_PROMPT | Wx::FD_SAVE)
if fd.show_modal == Wx::ID_OK
@filename = fd.get_path
on_file_close
@collection.clear
refresh_project
end
end end
def on_clickme(event) def on_clickme(event)
puts "I don't do anything" puts "I don't do anything"
end end
def on_edit_tileset def on_library_tileset
Tailor::GUI::TilesetEditor.new(self, Wx::ID_ANY, 'Tailor') Tailor::GUI::TilesetEditor.new(self, Wx::ID_ANY, 'Tailor :: Tileset').show
end
def on_library_manager
Tailor::GUI::LibraryManager.new(self,
Wx::ID_ANY,
'Tailor :: Library :: Manager').show
end end
def on_file_open def on_file_open
wildcards = "*.json"
fd = Wx::FileDialog.new(self, "Select collection to load",
:wildcard => wildcards,
:style => Wx::FD_FILE_MUST_EXIST | Wx::FD_OPEN)
if fd.show_modal == Wx::ID_OK
on_file_close
@filename = fd.get_path
@collection.load_json(@filename)
refresh_project
end
end
def on_file_saveas
wildcards = "*.json"
fd = Wx::FileDialog.new(self, "Select save location",
:wildcard => wildcards)
if fd.show_modal == Wx::ID_OK
@filename = fd.get_path
on_file_save
end
end end
def on_file_save def on_file_save
@collection.save_json(@filename)
@has_saved = true
end end
def on_file_export def on_file_export
end end
def on_file_close def on_file_close
@collection.clear
@menuFile.enable(@menuFileSave.get_id, false)
@menuFile.enable(@menuFileSaveAs.get_id, false)
@menuFile.enable(@menuFileExport.get_id, false)
@menuFile.enable(@menuFileClose.get_id, false)
@menuLibrary.enable(@menuLibraryManager.get_id, false)
if not @mainPanel.nil?
@mainPanel.destroy @mainPanel.destroy
@mainPanel = nil
end
end end
def on_help_about def on_help_about
@@ -81,6 +152,9 @@ module Tailor
:version => Tailor::VERSION, :version => Tailor::VERSION,
:description => ( :description => (
"Tailor : A program for stitching tilesets\n" + "Tailor : A program for stitching tilesets\n" +
"(C) 2014 Andrew Kesterson <andrew@aklabs.net>\n" +
"" +
"Released under the MIT License\n" +
"Please file bugs at https://github.com/akesterson/tailor" "Please file bugs at https://github.com/akesterson/tailor"
) )
) )

View File

@@ -7,8 +7,14 @@ require 'Tailor/Tileset'
module Tailor module Tailor
module GUI module GUI
class TilesetEditor < Wx::Frame class TilesetEditor < Wx::Frame
attr_accessor :has_saved
attr_accessor :has_loaded
def initialize(*args) def initialize(*args)
super(*args) super(*args)
self.has_saved = false
self.has_loaded = false
@tilesetFilename = "" @tilesetFilename = ""
@tilesetImage = nil @tilesetImage = nil
@tilesetNames = [] @tilesetNames = []
@@ -49,7 +55,11 @@ module Tailor
tmpversizer.add(@cancelBtn, 0, flag=Wx::EXPAND) tmpversizer.add(@cancelBtn, 0, flag=Wx::EXPAND)
rowsizer.add(tmpversizer, 0, flag = Wx::EXPAND|Wx::ALL) rowsizer.add(tmpversizer, 0, flag = Wx::EXPAND|Wx::ALL)
@tilesetSlicer = Tailor::GUI::GridDisplay.new(@panel, Wx::ID_ANY) @tilesetSlicer = Tailor::GUI::GridDisplay.new(@panel,
Wx::ID_ANY,
Wx::DEFAULT_POSITION,
Wx::DEFAULT_SIZE,
Wx::VSCROLL | Wx::HSCROLL | Wx::ALWAYS_SHOW_SB)
@tilesetSlicer.set_min_size(Wx::Size.new(320, 240)) @tilesetSlicer.set_min_size(Wx::Size.new(320, 240))
rowsizer.add(@tilesetSlicer, 1, flag = Wx::EXPAND|Wx::ALL) rowsizer.add(@tilesetSlicer, 1, flag = Wx::EXPAND|Wx::ALL)
evt_griddisplay_selected(@tilesetSlicer) { |event| on_gridSelected(event) } evt_griddisplay_selected(@tilesetSlicer) { |event| on_gridSelected(event) }
@@ -92,7 +102,14 @@ module Tailor
@panel.set_sizer(@sizer) @panel.set_sizer(@sizer)
@sizer.set_size_hints(self) @sizer.set_size_hints(self)
show() end
def disable_load
@loadBtn.disable
end
def disable_import
@importBtn.disable
end end
def on_CancelClicked(event) def on_CancelClicked(event)
@@ -115,6 +132,8 @@ module Tailor
@tilesetNames << "Tile #{i}" @tilesetNames << "Tile #{i}"
end end
@tileNameCtrl.disable @tileNameCtrl.disable
self.has_saved = false
self.has_loaded = true
end end
end end
@@ -153,6 +172,29 @@ module Tailor
end end
def set_tileset(tileset)
@tileset = tileset
tileset_changed
self.has_loaded = false
self.has_saved = false
end
def tileset_changed
# FIXME : This is redundant.
@tileset.tiles.each do |tile|
@tilesetNames << tile['name']
end
@tilesetImage = @tileset.image
@tilesetNameCtrl.set_value(@tileset.tileset_name)
@tilesetNotesCtrl.set_value(@tileset.notes)
@tilesetLicenseCtrl.set_value(@tileset.license)
@tileNameCtrl.disable
@tilesetSlicer.tileset = @tileset
@tilesetProperties.set_tileset(@tileset)
refresh_image
set_label("Tailor :: Tileset :: #{@tileset.tileset_name}")
end
def on_LoadClicked(event) def on_LoadClicked(event)
@tileset = Tailor::Tileset.new @tileset = Tailor::Tileset.new
wildcards = "*.json" wildcards = "*.json"
@@ -160,17 +202,11 @@ module Tailor
:wildcard => wildcards, :wildcard => wildcards,
:style => Wx::FD_FILE_MUST_EXIST) :style => Wx::FD_FILE_MUST_EXIST)
if fd.show_modal == Wx::ID_OK if fd.show_modal == Wx::ID_OK
@tileset.from_json(JSON.parse(File.read(fd.get_path))) @tileset.from_file(fd.get_path)
# FIXME : This is redundant. tileset_changed
@tileset.tiles.each do |tile|
@tilesetNames << tile['name']
end
@tilesetImage = @tileset.image
@tileNameCtrl.disable
@tilesetSlicer.tileset = @tileset
@tilesetProperties.set_tileset(@tileset)
refresh_image
end end
self.has_saved = false
self.has_loaded = true
end end
def on_SaveClicked(event) def on_SaveClicked(event)
@@ -197,11 +233,13 @@ module Tailor
File.open(filename, "w") do |file| File.open(filename, "w") do |file|
@tileset.write(file, callback) @tileset.write(file, callback)
end end
self.has_saved = true
end end
end end
def on_tilepropsChanged(event) def on_tilepropsChanged(event)
return if @tilesetSlicer.get_size < 1 return if @tilesetSlicer.get_size < 1
self.has_saved = false
ret = Wx::MessageDialog.new(self, ret = Wx::MessageDialog.new(self,
"Changing tile properties will reset all tile names. Continue?", "Changing tile properties will reset all tile names. Continue?",
"WARNING").show_modal "WARNING").show_modal
@@ -217,28 +255,28 @@ module Tailor
def on_tilesetNameChanged(event) def on_tilesetNameChanged(event)
@tileset.tileset_name = @tilesetNameCtrl.get_value @tileset.tileset_name = @tilesetNameCtrl.get_value
self.has_saved = false
end end
def on_tilesetLicenseChanged(event) def on_tilesetLicenseChanged(event)
@tileset.license = @tilesetLicenseCtrl.get_value @tileset.license = @tilesetLicenseCtrl.get_value
self.has_saved = false
end end
def on_tilesetNotesChanged(event) def on_tilesetNotesChanged(event)
@tileset.notes = @tilesetNotesCtrl.get_value @tileset.notes = @tilesetNotesCtrl.get_value
self.has_saved = false
end end
def on_tileNameChanged(event) def on_tileNameChanged(event)
@tilesetNames[@tilesetSlicer.get_selected_index] = @tileNameCtrl.get_value @tilesetNames[@tilesetSlicer.get_selected_index] = @tileNameCtrl.get_value
self.has_saved = false
end end
def refresh_image def refresh_image
begin begin
if @tilesetImage.is_ok if @tilesetImage.is_ok
@tilesetSlicer.set_image @tilesetImage @tilesetSlicer.set_image @tilesetImage
# The + 20 here is a hack to make scroll bars go away where we don't want them
x = ( @tilesetImage.get_width > 600 ? 600 : @tilesetImage.get_width + 20)
y = ( @tilesetImage.get_height > 400 ? 400 : @tilesetImage.get_height + 20)
@tilesetSlicer.set_min_size(Wx::Size.new(x, y))
@sizer.set_size_hints(self) @sizer.set_size_hints(self)
end end
rescue Exception => e rescue Exception => e

View File

@@ -1,33 +1,54 @@
require 'Tailor/Tileset' require 'Tailor/Tileset'
require 'singleton'
module Tailor module Tailor
class Library class Library
include Singleton
attr_accessor :tilesets
def initialize def initialize
self.tilesets = [] @tilesets = []
end end
def tileset_names def tileset_names
x = [] x = []
idx = 0 idx = 0
self.tilesets.each do |tileset| @tilesets.each do |tileset|
x << [idx, tileset.tileset_name] x << tileset.tileset_name
idx += 1 idx += 1
end end
x
end end
def unload_tileset(tileset) def each
self.tilesets.delete(tileset) @tilesets.each do |tileset|
yield tileset
end
end end
def add_tileset(path) def delete(tileset)
if tileset.instance_of?(String)
@tilesets.delete(by_name(tileset))
end
@tilesets.delete(tileset)
end
def add_tileset(tileset)
@tilesets << tileset if tileset.instance_of?(Tailor::Tileset)
end
def load_tileset(path)
ts = Tailor::Tileset.new ts = Tailor::Tileset.new
ts.from_json(JSON.parse(File.read(path))) ts.from_file(path)
self.tilesets << ts @tilesets << ts
return ts
end
def by_name(name)
@tilesets.each do |ts|
return ts if ts.tileset_name == name
end
end
def by_index(idx)
return @tilesets[idx]
end end
end end

View File

@@ -18,6 +18,7 @@ module Tailor
attr_accessor :tiles attr_accessor :tiles
def initialize def initialize
@filename = ''
self.image = nil self.image = nil
self.license = '' self.license = ''
self.notes = '' self.notes = ''
@@ -55,6 +56,11 @@ module Tailor
end end
end end
def get_filename
puts @filename
return @filename
end
def write(io_obj, callback = nil) def write(io_obj, callback = nil)
obj = self.to_json(callback) obj = self.to_json(callback)
if not callback.nil? if not callback.nil?
@@ -63,6 +69,20 @@ module Tailor
io_obj.write(JSON.pretty_generate(obj)) io_obj.write(JSON.pretty_generate(obj))
end end
def to_file(filename)
@filename = filename
File.open(filename, "w") do |file|
write(file)
end
end
def from_file(filename)
@filename = filename
File.open(filename, "r") do |file|
from_json(JSON.parse(file.read))
end
end
def from_json(js) def from_json(js)
self.tileset_name = js['name'] self.tileset_name = js['name']
self.license = js['license'] self.license = js['license']