-------------------------------------------------------------------------------------
-- Компонент редактора отвечающий за перемещение, вращение и масштабирование спрайтов
-- AA 2013
-------------------------------------------------------------------------------------

class 'Transform' (Node)

function Transform:__init(game_scene)
	Node.__init(self, game_scene:getMainEntity(), 'Transform', 1)
	self.game_scene = game_scene
	self.modes = { move = 0, rotate = 1, scale = 2, size = 3, zoom = 4 }
	self.current_mode = self.modes.move
	self.modified_objects = {}
	self.viewport_center = Vector2f(WSCR_W / 2, WSCR_H / 2)

	self:set_key_binds()
	self:init_controls()
	self:init_axis()
	self:set_selection_handlers()
end

-------------------------------------------------------------------------------------
function Transform:set_key_binds()
	self.key_binds = 
	{ 
		[ERSK_E] = self.modes.rotate, 
		[ERSK_Q] = self.modes.scale, 
		[ERSK_W] = self.modes.move,
		[ERSK_R] = self.modes.size,
		[ERSK_G] = self.modes.zoom,
	}

	for key, mode in pairs(self.key_binds) do
		self.game_scene:getWindow():getHotkeySignal(key):removeAll()
		self.game_scene:getWindow():getHotkeySignal(key):add(function() self:set_mode(mode) end)
	end

	self.arrows_binds =
	{
		[self.modes.move] =
		{
			[ERSK_LEFT] = function(object)
				object:setX(object:getX() - 1)
			end,
			[ERSK_UP] = function(object)
				object:setY(object:getY() - 1)
			end,
			[ERSK_RIGHT] = function(object)
				object:setX(object:getX() + 1)
			end,
			[ERSK_DOWN] = function(object)
				object:setY(object:getY() + 1)
			end,
		}
	}

	local function on_arrow_pressed(key)
		local current_selected_object = self.game_scene:getIngameEditor():get_selection():get_current_selected_object()
		if current_selected_object then
			self.arrows_binds[self.current_mode][key](current_selected_object)
		end
	end

	local arrows = { ERSK_LEFT, ERSK_UP, ERSK_RIGHT, ERSK_DOWN }
	for _, key in pairs(arrows) do
		self.game_scene:getWindow():getHotkeySignal(key):removeAll()
		self.game_scene:getWindow():getHotkeySignal(key):add(function() 
			on_arrow_pressed(key)
		end)
	end
end

-------------------------------------------------------------------------------------
function Transform:init_controls()
    if self.CreateLoaderTable then
		local table_resource = self:CreateLoaderTable()
		LoadScene(self.main_entity, table_resource)
	end
	self.controls = self:getEntityNamed('transform_controls')

	self:getEntityNamed('move').onPress:add(	function() self:set_mode(self.modes.move) end)
	self:getEntityNamed('rotate').onPress:add(	function() self:set_mode(self.modes.rotate) end)
	self:getEntityNamed('scale').onPress:add(	function() self:set_mode(self.modes.scale) end)
end

-------------------------------------------------------------------------------------
function Transform:init_axis()
	self.axis = 
	{
		parent = self:getEntityNamed('axis'),
		move = 
		{
			parent = self:getEntityNamed('move_axis'),
			x = self:getEntityNamed('move_axis_x'),
			y = self:getEntityNamed('move_axis_y'),
			xy = self:getEntityNamed('move_axis_xy'),
		},
		rotate = self:getEntityNamed('rotate_axis'),
		scale = 
		{
			parent = self:getEntityNamed('scale_axis'),
			x = self:getEntityNamed('scale_axis_x'),
			y = self:getEntityNamed('scale_axis_y'),
			xy = self:getEntityNamed('scale_axis_xy'),
		},
		size =
		{
			parent = self:getEntityNamed('size_axis'),
			x = self:getEntityNamed('size_axis_x'),
			y = self:getEntityNamed('size_axis_y'),
			xy = self:getEntityNamed('size_axis_xy'),
		},
		zoom_plane = self:getEntityNamed('zoom_plane'),
	}

	self.axis.parent:hide()
	self.axis.parent:setPosition(Vector2f(0,0))
	self.axis.zoom_plane:hide()

	local axis_inactive_opacity = .65
	local axis_active_opacity = 1
	for id, axis in pairs(self.axis.move) do 
		axis:setOpacity(axis_inactive_opacity)
		axis.onFocusIn:add(function() 
			axis:destroyEffectors()
			axis:ChangeOpacity(axis:getOpacity(), axis_active_opacity, .1) 
		end)
		axis.onFocusOut:add(function() 
			axis:destroyEffectors()
			axis:ChangeOpacity(axis:getOpacity(), axis_inactive_opacity, .1) 
		end)
	end
	for id, axis in pairs(self.axis.scale) do 
		axis:setOpacity(axis_inactive_opacity)
		axis.onFocusIn:add(function() 
			axis:destroyEffectors()
			axis:ChangeOpacity(axis:getOpacity(), axis_active_opacity, .1) 
		end)
		axis.onFocusOut:add(function() 
			axis:destroyEffectors()
			axis:ChangeOpacity(axis:getOpacity(), axis_inactive_opacity, .1) 
		end)
	end
	for id, axis in pairs(self.axis.size) do 
		axis:setOpacity(axis_inactive_opacity)
		axis.onFocusIn:add(function() 
			axis:destroyEffectors()
			axis:ChangeOpacity(axis:getOpacity(), axis_active_opacity, .1) 
		end)
		axis.onFocusOut:add(function() 
			axis:destroyEffectors()
			axis:ChangeOpacity(axis:getOpacity(), axis_inactive_opacity, .1) 
		end)
	end
	self.axis.rotate:setOpacity(axis_inactive_opacity)
	self.axis.rotate.onFocusIn:add(function() 
		self.axis.rotate:destroyEffectors()
		self.axis.rotate:ChangeOpacity(self.axis.rotate:getOpacity(), axis_active_opacity, .1) 
	end)
	self.axis.rotate.onFocusOut:add(function() 
		self.axis.rotate:destroyEffectors()
		self.axis.rotate:ChangeOpacity(self.axis.rotate:getOpacity(), axis_inactive_opacity, .1) 
	end)
end

-------------------------------------------------------------------------------------
function Transform:set_selection_handlers()
	local function hide_axis()
		self.axis.move.parent:hide()
		self.axis.rotate:hide()
		self.axis.scale.parent:hide()
		self.axis.size.parent:hide()
		self.axis.zoom_plane:hide()
	end

	local function scale_object_axis(axis, object)
		if object:getScale().x > 0 then
			axis:setScaleX(1 / object:getScale().x)
		else
			axis:setScaleX(1 / -object:getScale().x)
		end

		if object:getScale().y > 0 then
			axis:setScaleY(1 / object:getScale().y)
		else
			axis:setScaleY(1 / -object:getScale().y)
		end
	end

	local function isnan(n) 
		return tostring(n) == '-1.#IND' 
	end

	local function on_sprite_transformed(object)
		self.game_scene:getIngameEditor():on_sprite_transformed(object)
	end

	self.select_object_handlers =
	{
		[self.modes.move] = function(object)
			hide_axis()
			self.axis.move.parent:show()
			self.axis.move.parent:attachTo(object)
			scale_object_axis(self.axis.move.parent, object)

			local offset = Vector2f(0, 0)

			-- moving xy plane ------------------------------
			self.axis.move.xy.onClickBegin:removeAll()
			self.axis.move.xy.onClickBegin:add( function(target, screenFocus)
				offset = Vector2f(screenFocus:getScrX() - object:getScrX(),
									screenFocus:getScrY() - object:getScrY())
				screenFocus:startDrag(self.axis.move.xy) 
			end)

			self.axis.move.xy.onDragFocusKeep:removeAll()
			self.axis.move.xy.onDragFocusKeep:add( function(target, screenFocus) 
				object:setScrXY(screenFocus:getScrX() - offset.x, screenFocus:getScrY() - offset.y)
				on_sprite_transformed(object)
			end)
			-----------------------------------------------

			-- moving only y plane ------------------------
			self.axis.move.y.onClickBegin:removeAll()
			self.axis.move.y.onClickBegin:add( function(target, screenFocus) 
				offset = Vector2f(screenFocus:getScrX() - object:getScrX(),
									screenFocus:getScrY() - object:getScrY())
				screenFocus:startDrag(self.axis.move.y) 
			end)

			self.axis.move.y.onDragFocusKeep:removeAll()
			self.axis.move.y.onDragFocusKeep:add( function(target, screenFocus) 
				object:setScrXY(object:getScrX(), screenFocus:getScrY() - offset.y)
				on_sprite_transformed(object)
			end)
			-------------------------------------------------

			-- moving only x plane ------------------------
			self.axis.move.x.onClickBegin:removeAll()
			self.axis.move.x.onClickBegin:add( function(target, screenFocus) 
				offset = Vector2f(screenFocus:getScrX() - object:getScrX(),
									screenFocus:getScrY() - object:getScrY())
				screenFocus:startDrag(self.axis.move.x) 
			end)

			self.axis.move.x.onDragFocusKeep:removeAll()
			self.axis.move.x.onDragFocusKeep:add( function(target, screenFocus) 
				object:setScrXY(screenFocus:getScrX() - offset.x, object:getScrY())
				on_sprite_transformed(object)
			end)
			-------------------------------------------------
		end,
		[self.modes.rotate] = function(object)
			hide_axis()
			self.axis.rotate:show()
			self.axis.rotate:attachTo(object)
			scale_object_axis(self.axis.rotate, object)

			local offset = Vector2f(0, 0)
			local start_angle = 0

			self.axis.rotate.onClickBegin:removeAll()
			self.axis.rotate.onClickBegin:add( function(target, screenFocus) 
				offset = Vector2f(screenFocus:getScrX() - object:getScrX(),
									screenFocus:getScrY() - object:getScrY())
				start_angle = object:getRotationRad()
				screenFocus:startDrag(self.axis.rotate) 
			end)

			self.axis.rotate.onDragFocusKeep:removeAll()
			self.axis.rotate.onDragFocusKeep:add( function(target, screenFocus) 
				local a = offset
				local b = Vector2f(screenFocus:getScrX() - object:getScrX(), screenFocus:getScrY() - object:getScrY())

				local dangle = math.acos((a.x * b.x + a.y * b.y) / (math.sqrt(a.x*a.x + a.y*a.y)*math.sqrt(b.x*b.x + b.y*b.y)))
				if not isnan(dangle) then
					local cross_product = a.x*b.y - a.y*b.x
					if cross_product > 0 then
						object:setRotationRad(start_angle + dangle)
					else
						object:setRotationRad(start_angle + 2*M_PI - dangle)
					end
					on_sprite_transformed(object)
				end
			end)
		end,
		[self.modes.scale] = function(object)
			hide_axis()
			self.axis.scale.parent:show()
			self.axis.scale.parent:attachTo(object)
			scale_object_axis(self.axis.scale.parent, object)

			local scale_sensetivity = 100
			local scale_rate = .01
			local start_vec = Vector2f(0, 0)
			local start_object_scale = Vector2f(1, 1)

			-- scaling xy plane ------------------------------
			self.axis.scale.xy.onClickBegin:removeAll()
			self.axis.scale.xy.onClickBegin:add( function(target, screenFocus) 
				start_vec = Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				start_object_scale = object:getScale()
				scale_rate = math.max(start_object_scale.x, start_object_scale.y) / scale_sensetivity
				screenFocus:startDrag(self.axis.scale.xy) 
			end)

			self.axis.scale.xy.onDragFocusKeep:removeAll()
			self.axis.scale.xy.onDragFocusKeep:add( function(target, screenFocus)
				local delta_vec = start_vec - Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				object:setScaleY((start_object_scale.y + delta_vec.y * scale_rate))
				object:setScaleX((start_object_scale.x - delta_vec.x * scale_rate))
				on_sprite_transformed(object)
			end)

			self.axis.scale.xy.onDragFinish:removeAll()
			self.axis.scale.xy.onDragFinish:add( function(target, screenFocus) 
				scale_object_axis(self.axis.scale.parent, object)
			end) 
			-----------------------------------------------

			-- scaling only y plane ------------------------
			self.axis.scale.y.onClickBegin:removeAll()
			self.axis.scale.y.onClickBegin:add( function(target, screenFocus) 
				start_vec = Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				start_object_scale = object:getScale()
				scale_rate = object:getScale().y / 200
				screenFocus:startDrag(self.axis.scale.y) 
			end)

			self.axis.scale.y.onDragFocusKeep:removeAll()
			self.axis.scale.y.onDragFocusKeep:add( function(target, screenFocus)
				local delta_vec = start_vec - Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				object:setScaleY(start_object_scale.y + delta_vec.y * scale_rate)
				on_sprite_transformed(object)
			end)

			self.axis.scale.y.onDragFinish:removeAll()
			self.axis.scale.y.onDragFinish:add( function(target, screenFocus) 
				scale_object_axis(self.axis.scale.parent, object)
			end) 
			-------------------------------------------------

			-- scaling only x plane ------------------------
			self.axis.scale.x.onClickBegin:removeAll()
			self.axis.scale.x.onClickBegin:add( function(target, screenFocus) 
				start_vec = Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				start_object_scale = object:getScale()
				scale_rate = object:getScale().x / 200
				screenFocus:startDrag(self.axis.scale.x) 
			end)

			self.axis.scale.x.onDragFocusKeep:removeAll()
			self.axis.scale.x.onDragFocusKeep:add( function(target, screenFocus) 
				local delta_vec = start_vec - Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				object:setScaleX(start_object_scale.x - delta_vec.x * scale_rate)
				on_sprite_transformed(object)
			end)

			self.axis.scale.x.onDragFinish:removeAll()
			self.axis.scale.x.onDragFinish:add( function(target, screenFocus) 
				scale_object_axis(self.axis.scale.parent, object)
			end) 
			-------------------------------------------------
		end, 
		[self.modes.size] = function(object)
			hide_axis()
			self.axis.size.parent:show()
			self.axis.size.parent:attachTo(object)
			scale_object_axis(self.axis.size.parent, object)

			local size_sensetivity = 100
			local size_rate = .01
			local start_vec = Vector2f(0, 0)
			local start_object_size = Vector2f(1, 1)

			-- resizing xy plane ------------------------------
			self.axis.size.xy.onClickBegin:removeAll()
			self.axis.size.xy.onClickBegin:add( function(target, screenFocus) 
				start_vec = Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				start_object_size = object:getSize()
				size_rate = math.max(start_object_size.x, start_object_size.y) / size_sensetivity
				screenFocus:startDrag(self.axis.size.xy) 
			end)

			self.axis.size.xy.onDragFocusKeep:removeAll()
			self.axis.size.xy.onDragFocusKeep:add( function(target, screenFocus)
				local delta_vec = start_vec - Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				object:setSize(start_object_size.x - delta_vec.x * size_rate, start_object_size.y + delta_vec.y * size_rate)
				on_sprite_transformed(object)
			end)

			self.axis.size.xy.onDragFinish:removeAll()
			self.axis.size.xy.onDragFinish:add( function(target, screenFocus) 
				scale_object_axis(self.axis.size.parent, object)
				on_sprite_transformed(object)
			end) 
			-----------------------------------------------

			-- resizing only y plane ------------------------
			self.axis.size.y.onClickBegin:removeAll()
			self.axis.size.y.onClickBegin:add( function(target, screenFocus) 
				start_vec = Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				start_object_size = object:getSize()
				size_rate = object:getSize().y / 200
				screenFocus:startDrag(self.axis.size.y) 
			end)

			self.axis.size.y.onDragFocusKeep:removeAll()
			self.axis.size.y.onDragFocusKeep:add( function(target, screenFocus)
				local delta_vec = start_vec - Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				object:setSize(start_object_size.x, start_object_size.y + delta_vec.y * size_rate)
				on_sprite_transformed(object)
			end)

			self.axis.size.y.onDragFinish:removeAll()
			self.axis.size.y.onDragFinish:add( function(target, screenFocus) 
				scale_object_axis(self.axis.size.parent, object)
				on_sprite_transformed(object)
			end) 
			-------------------------------------------------

			-- resizing only x plane ------------------------
			self.axis.size.x.onClickBegin:removeAll()
			self.axis.size.x.onClickBegin:add( function(target, screenFocus) 
				start_vec = Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				start_object_size = object:getSize()
				size_rate = object:getSize().x / 200
				screenFocus:startDrag(self.axis.size.x) 
			end)

			self.axis.size.x.onDragFocusKeep:removeAll()
			self.axis.size.x.onDragFocusKeep:add( function(target, screenFocus) 
				local delta_vec = start_vec - Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				object:setSize(start_object_size.x - delta_vec.x * size_rate, start_object_size.y)
				on_sprite_transformed(object)
			end)

			self.axis.size.x.onDragFinish:removeAll()
			self.axis.size.x.onDragFinish:add( function(target, screenFocus) 
				scale_object_axis(self.axis.size.parent, object)
				on_sprite_transformed(object)
			end) 
			-------------------------------------------------
		end,
		[self.modes.zoom] = function(object)
			hide_axis()
			self.axis.zoom_plane:show()

			local scale_sensetivity = 100
			local scale_rate = .01
			local start_vec = Vector2f(0, 0)
			local start_object_scale = Vector2f(1, 1)
			local start_object_position = Vector2f(0, 0)

			local playfield_main_entity = self.game_scene:getPlayField():getMainEntity()
			-- print(string.format('hot spot x: %d, y: %d', playfield_main_entity:getHotSpot().x, playfield_main_entity:getHotSpot().y))

			self.axis.zoom_plane.onClickBegin:removeAll()
			self.axis.zoom_plane.onClickBegin:add( function(target, screenFocus)
				start_vec = Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				start_object_scale = playfield_main_entity:getScale()
				start_object_position = playfield_main_entity:getPosition()
				scale_rate = math.max(start_object_scale.x, start_object_scale.y) / scale_sensetivity
				-- scale_rate = 1
				screenFocus:startDrag(self.axis.zoom_plane)  
			end)

			self.axis.zoom_plane.onDragFocusKeep:removeAll()
			self.axis.zoom_plane.onDragFocusKeep:add( function(target, screenFocus)
				local delta_vec = start_vec - Vector2f(screenFocus:getScrX(), screenFocus:getScrY())
				-- local new_scale = math.max(start_object_scale.y + delta_vec.y * scale_rate, start_object_scale.x - delta_vec.x * scale_rate)
				local new_scale = start_object_scale.y + delta_vec.y * scale_rate
				playfield_main_entity:setScaleY(new_scale)
				playfield_main_entity:setScaleX(new_scale)

				playfield_main_entity:setXY(start_object_position.x + delta_vec.x * 1, start_object_position.y - delta_vec.y * 1)
				print(string.format('playfield position x: %d, y: %d', playfield_main_entity:getX(), playfield_main_entity:getY()))
			end)

			self.axis.zoom_plane.onDragFinish:removeAll()
			self.axis.zoom_plane.onDragFinish:add( function(target, screenFocus)
				-- playfield_main_entity:setHotSpot() 
			end) 
		end
	}
end

-------------------------------------------------------------------------------------
function Transform:set_mode(mode)
	if self.enabled then		
		if self.current_mode ~= mode then
			self.current_mode = mode
			local current_selected_object = self.game_scene:getIngameEditor():get_selection():get_current_selected_object()
			if current_selected_object then
				self:on_object_selected(current_selected_object)
			end
			print('setting transform mode to '..tostring(self.current_mode))
		end
	end
end

-------------------------------------------------------------------------------------
function Transform:on_object_selected(object)
	if self.enabled then
		self.select_object_handlers[self.current_mode](object)
		self.modified_objects[object:getName()] = true
	end
end

-------------------------------------------------------------------------------------
function Transform:on_selection_removed()
	self.axis.move.parent:attachTo(self.axis.parent)
	self.axis.rotate:attachTo(self.axis.parent)
	self.axis.scale.parent:attachTo(self.axis.parent)
	self.axis.size.parent:attachTo(self.axis.parent)
	self.axis.zoom_plane:attachTo(self.axis.parent)
end

-------------------------------------------------------------------------------------
function Transform:save()
	print('saving...')
	local playfield = self.game_scene:getPlayField()

	local top_zoom_zone = playfield.active_zones:GetTop()
	local script_path = top_zoom_zone and playfield:getZoomZonePath(top_zoom_zone:getName()) or playfield:getPathLua()
	local script_lines = {}
	local loader_table_lines = {}

	local parsing_loader_table = false
	for line in io.lines(script_path) do
		if string.find(line, 'CreateLoaderTable') or parsing_loader_table then
			parsing_loader_table = true
			table.insert(loader_table_lines, line)
		else
			table.insert(script_lines, line)
		end
	end

	local function string_insert(value, insert, place)
		if place == nil then
			place = string.len(value)+1
		end
		return string.sub(value, 1,place-1) .. string.gsub(string.sub(value, place,place), string.sub(value, place,place), insert) .. string.sub(value, place, string.len(value))
	end

	local function add_to_desc_table(value, insert)
		return string_insert(value, insert, string.len(value) - 2)
	end

	for object_name, _ in pairs(self.modified_objects) do
		-- find line describing this object
		for key, line in pairs(loader_table_lines) do
			if string.find(line, 'name = \''..object_name..'\'') then
				local current_object = playfield:getEntityNamed(object_name)

				-- x, y position
				loader_table_lines[key] = string.gsub(loader_table_lines[key], 'x = .-,', string.format('x = %d,', current_object:getX()), 1)
				loader_table_lines[key] = string.gsub(loader_table_lines[key], 'y = .-,', string.format('y = %d,', current_object:getY()), 1)
				loader_table_lines[key] = string.gsub(loader_table_lines[key], 'order = .-,', string.format('order = %d,', current_object:getOrder()))

				-- scale X ------------------------------------------------------
				if string.find(loader_table_lines[key], 'scaleX = ') then
					loader_table_lines[key] = string.gsub(loader_table_lines[key], 'scaleX = .-,', string.format('scaleX = %.2f,', current_object:getScale().x))
				else
					loader_table_lines[key] = add_to_desc_table(loader_table_lines[key], string.format('scaleX = %.2f, ', current_object:getScale().x))
				end

				-- scale Y ------------------------------------------------------
				if string.find(loader_table_lines[key], 'scaleY = ') then
					loader_table_lines[key] = string.gsub(loader_table_lines[key], 'scaleY = .-,', string.format('scaleY = %.2f,', current_object:getScale().y))
				else
					loader_table_lines[key] = add_to_desc_table(loader_table_lines[key], string.format('scaleY = %.2f, ', current_object:getScale().y))
				end

				-- width --------------------------------------------------------
				if string.find(loader_table_lines[key], 'width = ') then
					loader_table_lines[key] = string.gsub(loader_table_lines[key], 'width = .-,', string.format('width = %.2f,', current_object:getSize().x))
				else
					loader_table_lines[key] = add_to_desc_table(loader_table_lines[key], string.format('width = %.2f, ', current_object:getSize().x))
				end

				-- height --------------------------------------------------------
				if string.find(loader_table_lines[key], 'height = ') then
					loader_table_lines[key] = string.gsub(loader_table_lines[key], 'height = .-,', string.format('height = %.2f,', current_object:getSize().y))
				else
					loader_table_lines[key] = add_to_desc_table(loader_table_lines[key], string.format('height = %.2f, ', current_object:getSize().y))
				end

				-- angle ------------------------------------------------------
				local normalized_angle = (current_object:getRotationDeg() % 360 < 0) and (current_object:getRotationDeg() + 360) or current_object:getRotationDeg() % 360
				if string.find(loader_table_lines[key], 'angle = ') then
					loader_table_lines[key] = string.gsub(loader_table_lines[key], 'angle = .-,', string.format('angle = %.2f,', normalized_angle))
				else
					loader_table_lines[key] = add_to_desc_table(loader_table_lines[key], string.format('angle = %.2f, ', current_object:getRotationDeg()))
				end

				-- opacity ------------------------------------------------------
				if string.find(loader_table_lines[key], 'opacity = ') then
					loader_table_lines[key] = string.gsub(loader_table_lines[key], 'opacity = .-,', string.format('opacity = %.2f,', current_object:getOpacity()))
				else
					loader_table_lines[key] = add_to_desc_table(loader_table_lines[key], string.format('opacity = %.2f, ', current_object:getOpacity()))
				end

				-- color ------------------------------------------------------
				local toggle_highlight = false
				if self.game_scene.is_objects_highlighted then
					playfield:toggleHighlightObjects()
					toggle_highlight = true
				end
				if string.find(loader_table_lines[key], 'color = ') then
					local c = current_object:getColor()
					loader_table_lines[key] = string.gsub(loader_table_lines[key], 'color = .-},', string.format('color = {r = %.2f, g = %.2f, b = %.2f, a = %.2f},', c:getR(), c:getG(), c:getB(), c:getA()))
				else
					local c = current_object:getColor()
					loader_table_lines[key] = add_to_desc_table(loader_table_lines[key], string.format('color = {r = %.2f, g = %.2f, b = %.2f, a = %.2f}, ', c:getR(), c:getG(), c:getB(), c:getA()))
				end
				if toggle_highlight then playfield:toggleHighlightObjects() end
			end
		end
	end

	local script_file = io.open(script_path, 'w+')
	for key, line in pairs(script_lines) do
		script_file:write(line..'\n')
	end
	for key, line in pairs(loader_table_lines) do
		script_file:write(line..'\n')
	end
	script_file:close()
	self.modified_objects = {}
end

-------------------------------------------------------------------------------------
function Transform:enable()
	self.enabled = true
	self.controls:show()
end

-------------------------------------------------------------------------------------
function Transform:disable()
	self.enabled = false
	self.controls:hide()
	self.axis.move.parent:hide()
	self.axis.scale.parent:hide()
	self.axis.size.parent:hide()
	self.axis.rotate:hide()
	self.axis.zoom_plane:hide()
	self:on_selection_removed()
end

--------------------------------------------------------------------------------
--                      GENERATED CONTENT. DO NOT EDIT.                       --
--------------------------------------------------------------------------------

function Transform:CreateLoaderTable()
	local objects =
	{
		{ name = 'transform_controls',  entityType = 'SpriteEntity',  x = 973,  y = 17,  order = 0,  color = {r = 1, g = 1, b = 1, a = 0.00392157},  editingLocked = false,  treeItemIsExpanded = false,  width = 100,  height = 24,  },
		{ name = 'move',  entityType = 'SpriteEntity',  parentName = 'transform_controls',  x = -33,  y = -3,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/move.png',  width = 33,  height = 22,  },
		{ name = 'rotate',  entityType = 'SpriteEntity',  parentName = 'transform_controls',  x = 0,  y = -3,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/rotate.png',  width = 33,  height = 22,  },
		{ name = 'scale',  entityType = 'SpriteEntity',  parentName = 'transform_controls',  x = 32,  y = -3,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/scale.png',  width = 32,  height = 22,  },
		{ name = 'axis',  entityType = 'SpriteEntity',  x = 512,  y = 384,  order = 0,  color = {r = 1, g = 1, b = 1, a = 0},  editingLocked = false,  treeItemIsExpanded = true,  width = 100,  height = 100,  },
		{ name = 'move_axis',  entityType = 'SpriteEntity',  parentName = 'axis',  x = 0,  y = 0,  order = 0,  color = {r = 1, g = 1, b = 1, a = 0},  editingLocked = false,  treeItemIsExpanded = false,  width = 1,  height = 1,  },
		{ name = 'move_axis_x',  entityType = 'SpriteEntity',  parentName = 'move_axis',  x = 58,  y = 0,  order = 5,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/move_axis/axis_x.png',  width = 113,  height = 29,  },
		{ name = 'move_axis_y',  entityType = 'SpriteEntity',  parentName = 'move_axis',  x = 0,  y = -59,  order = 5,  editingLocked = false,  treeItemIsExpanded = false,  texturePath = 'Data/Textures/Screens/IngameEditor/move_axis/axis_y.png',  width = 30,  height = 113,  },
		{ name = 'move_axis_xy',  entityType = 'SpriteEntity',  parentName = 'move_axis',  x = 30,  y = -30,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/axis_xy.png',  width = 55,  height = 54,  },
		{ name = 'scale_axis',  entityType = 'SpriteEntity',  parentName = 'axis',  x = 0,  y = 0,  order = 0,  color = {r = 1, g = 1, b = 1, a = 0},  editingLocked = false,  treeItemIsExpanded = false,  width = 100,  height = 100,  },
		{ name = 'scale_axis_x',  entityType = 'SpriteEntity',  parentName = 'scale_axis',  x = 55,  y = 0,  order = 0,  scaleX = 1,  scaleY = -1,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/scale_axis/scale_axis_x.png',  width = 108,  height = 25,  },
		{ name = 'scale_axis_y',  entityType = 'SpriteEntity',  parentName = 'scale_axis',  x = 0,  y = -57,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/scale_axis/scale_axis_y.png',  width = 25,  height = 108,  },
		{ name = 'scale_axis_xy',  entityType = 'SpriteEntity',  parentName = 'scale_axis',  x = 30,  y = -30,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/axis_xy.png',  width = 55,  height = 54,  },
		{ name = 'size_axis',  entityType = 'SpriteEntity',  parentName = 'axis',  x = 0,  y = 0,  order = 0,  color = {r = 1, g = 1, b = 1, a = 0},  editingLocked = false,  treeItemIsExpanded = false,  width = 100,  height = 100,  },
		{ name = 'size_axis_x',  entityType = 'SpriteEntity',  parentName = 'size_axis',  x = 55,  y = 0,  order = 0,  scaleX = 1,  scaleY = -1,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/size_axis/size_axis_x.png',  width = 108,  height = 25,  },
		{ name = 'size_axis_y',  entityType = 'SpriteEntity',  parentName = 'size_axis',  x = 0,  y = -57,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/size_axis/size_axis_y.png',  width = 25,  height = 108,  },
		{ name = 'size_axis_xy',  entityType = 'SpriteEntity',  parentName = 'size_axis',  x = 30,  y = -30,  order = 0,  editingLocked = false,  treeItemIsExpanded = true,  texturePath = 'Data/Textures/Screens/IngameEditor/axis_xy.png',  width = 55,  height = 54,  },
		{ name = 'rotate_axis',  entityType = 'SpriteEntity',  parentName = 'axis',  x = -1,  y = -0.999969,  order = 5,  editingLocked = false,  treeItemIsExpanded = true,  hotSpot = {x = 56, y = 84},  texturePath = 'Data/Textures/Screens/IngameEditor/rotate_axis/rotate_axis.png',  width = 140,  height = 142,  },
		{ name = 'zoom_plane',  entityType = 'SpriteEntity',  x = 512,  y = 384,  order = 100,  color = {r = 1, g = 1, b = 1, a = 0.00392157},  editingLocked = false,  treeItemIsExpanded = true,  width = 1366,  height = 768,  },
	}
	return objects
end
