Image
FO_Channels = {}

FO_Channels.includeChildLayers = true
FO_Channels.visibleLayersOnly = false
FO_Channels.selectedLayersOnly = false
FO_Channels.filterOutLayersExpr = nil

FO_Channels.layerChannels = true
FO_Channels.windChannels = true
FO_Channels.pointChannels = true
FO_Channels.selectedPointsOnly = false
FO_Channels.boneChannels = true
FO_Channels.selectedBonesOnly = false
FO_Channels.shapeChannels = true
FO_Channels.selectedShapesOnly = false
FO_Channels.switchChannels = true
FO_Channels.particleChannels = true
FO_Channels.layerOrderChannels = true
FO_Channels.trackingPointChannels = true
FO_Channels.audioChannels = true
FO_Channels.layerMarkerChannels = true
FO_Channels.cameraChannels = true
FO_Channels.documentMarkerChannels = true

function FO_Channels:LoadPrefs(prefs)
	-- * Layers:
	self.includeChildLayers = prefs:GetBool("FO_Channels.includeChildLayers", true)
	self.visibleLayersOnly = prefs:GetBool("FO_Channels.visibleLayersOnly", false)
	self.selectedLayersOnly = prefs:GetBool("FO_Channels.selectedLayersOnly", false)
	self.timelineVisibleLayersOnly = prefs:GetBool("FO_Channels.timelineVisibleLayersOnly", false)
	self.animTaggedLayersOnly = prefs:GetBool("FO_Channels.animTaggedLayersOnly", false)
	self.filterOutLayersExpr = prefs:GetString("FO_Channels.filterOutLayersExpr", "")
	-- * Channels:
	self.layerChannels = prefs:GetBool("FO_Channels.layerChannels", true)
	self.windChannels = prefs:GetBool("FO_Channels.windChannels", true)
	self.pointChannels = prefs:GetBool("FO_Channels.pointChannels", true)
	self.selectedPointsOnly = prefs:GetBool("FO_Channels.selectedPointsOnly", false)
	self.boneChannels = prefs:GetBool("FO_Channels.boneChannels", true)
	self.selectedBonesOnly = prefs:GetBool("FO_Channels.selectedBonesOnly", false)
	self.shapeChannels = prefs:GetBool("FO_Channels.shapeChannels", true)
	self.selectedShapesOnly = prefs:GetBool("FO_Channels.selectedShapesOnly", false)
	self.switchChannels = prefs:GetBool("FO_Channels.switchChannels", true)
	self.particleChannels = prefs:GetBool("FO_Channels.particleChannels", true)
	self.layerOrderChannels = prefs:GetBool("FO_Channels.layerOrderChannels", true)
	self.trackingPointChannels = prefs:GetBool("FO_Channels.trackingPointChannels", true)
	self.audioChannels = prefs:GetBool("FO_Channels.audioChannels", true)
	self.layerMarkerChannels = prefs:GetBool("FO_Channels.layerMarkerChannels", true)
	self.cameraChannels = prefs:GetBool("FO_Channels.cameraChannels", true)
	self.documentMarkerChannels = prefs:GetBool("FO_Channels.documentMarkerChannels", true)
end

function FO_Channels:SavePrefs(prefs)
	-- * Layers:
	prefs:SetBool("FO_Channels.includeChildLayers", self.includeChildLayers)
	prefs:SetBool("FO_Channels.visibleLayersOnly", self.visibleLayersOnly)
	prefs:SetBool("FO_Channels.selectedLayersOnly", self.selectedLayersOnly)
	prefs:SetBool("FO_Channels.timelineVisibleLayersOnly", self.timelineVisibleLayersOnly)
	prefs:SetBool("FO_Channels.animTaggedLayersOnly", self.animTaggedLayersOnly)
	prefs:SetString("FO_Channels.filterOutLayersExpr", self.filterOutLayersExpr)
	-- * Channels:
	prefs:SetBool("FO_Channels.layerChannels", self.layerChannels)
	prefs:SetBool("FO_Channels.windChannels", self.windChannels)
	prefs:SetBool("FO_Channels.pointChannels", self.pointChannels)
	prefs:SetBool("FO_Channels.selectedPointsOnly", self.selectedPointsOnly)
	prefs:SetBool("FO_Channels.boneChannels", self.boneChannels)
	prefs:SetBool("FO_Channels.selectedBonesOnly", self.selectedBonesOnly)
	prefs:SetBool("FO_Channels.shapeChannels", self.shapeChannels)
	prefs:SetBool("FO_Channels.switchChannels", self.switchChannels)
	prefs:SetBool("FO_Channels.particleChannels", self.particleChannels)
	prefs:SetBool("FO_Channels.layerOrderChannels", self.layerOrderChannels)
	prefs:SetBool("FO_Channels.trackingPointChannels", self.trackingPointChannels)
	prefs:SetBool("FO_Channels.audioChannels", self.audioChannels)
	prefs:SetBool("FO_Channels.layerMarkerChannels", self.layerMarkerChannels)
	prefs:SetBool("FO_Channels.cameraChannels", self.cameraChannels)
	prefs:SetBool("FO_Channels.documentMarkerChannels", self.documentMarkerChannels)
end

function FO_Channels:ResetPrefs()
	-- * Layers:
	self.includeChildLayers = true
	self.visibleLayersOnly = false
	self.selectedLayersOnly = false
	self.timelineVisibleLayersOnly = false
	self.animTaggedLayersOnly = false
	self.filterOutLayersExpr = ""
	-- * Channels:
	self.layerChannels = true
	self.windChannels = true
	self.pointChannels = true
	self.selectedPointsOnly = false
	self.boneChannels = true
	self.selectedBonesOnly = false
	self.shapeChannels = true
	self.selectedShapesOnly = false
	self.switchChannels = true
	self.particleChannels = true
	self.layerOrderChannels = true
	self.trackingPointChannels = true
	self.audioChannels = true
	self.layerMarkerChannels = true
	self.cameraChannels = true
	self.documentMarkerChannels = true
end

function FO_Channels:DoLayout(moho, layout, msg_base)
	globalTool = moho:CurrentTool()
	-- *******************	
	-- *** Messages:   ***
	-- *******************
	self.msg_base = msg_base
	-- * Toggle Layers:
	self.TOGGLE_CHILD_LAYERS 							= self.msg_base
	self.TOGGLE_VISIBLE_LAYERS_ONLY						= self.msg_base + 1
	self.TOGGLE_SELECTED_LAYERS_ONLY					= self.msg_base + 2
	self.TOGGLE_TIMELINE_VISIBLE_LAYERS_ONLY 			= self.msg_base + 3
	self.TOGGLE_ANIM_TAGGED_LAYERS_ONLY					= self.msg_base + 20--*
	self.TOGGLE_FILTER_LAYER_EXPRESSIONS				= self.msg_base + 21
	-- * Toggle Channels:
	self.TOGGLE_LAYER_CHANNELS							= self.msg_base + 4
	self.TOGGLE_WIND_CHANNELS							= self.msg_base + 5
	self.TOGGLE_POINT_CHANNELS 							= self.msg_base + 6
	self.TOGGLE_SELECTED_POINTS_ONLY 					= self.msg_base + 7
	self.TOGGLE_BONE_CHANNELS 							= self.msg_base + 8
	self.TOGGLE_SELECTED_BONES_ONLY 					= self.msg_base + 9
	self.TOGGLE_SHAPE_CHANNELS 							= self.msg_base + 10
	self.TOGGLE_SELECTED_SHAPES_ONLY 					= self.msg_base + 11
	self.TOGGLE_SWITCH_CHANNELS 						= self.msg_base + 12
	self.TOGGLE_PARTICLE_CHANNELS 						= self.msg_base + 13
	self.TOGGLE_LAYER_ORDER_CHANNELS 				 	= self.msg_base + 14
	self.TOGGLE_TRACKING_POINT_CHANNELS 				= self.msg_base + 15
	self.TOGGLE_AUDIO_CHANNELS 							= self.msg_base + 16
	self.TOGGLE_CAMERA_CHANNELS 						= self.msg_base + 17
	self.TOGGLE_LAYER_MARKER_CHANNELS 					= self.msg_base + 18
	self.TOGGLE_DOCUMENT_MARKER_CHANNELS 				= self.msg_base + 19
	self.LAST_MESSAGE 									= self.msg_base + 22 -- * Is not actually used, but keep this up to date for the HandleMessage function.
	
	if moho ~= nil then -- * In case DoLayout is called from a dialog.
		local tool = moho:CurrentTool()
		self.tweenTool = (tool == "LK_TweenMachine")
		self.keyTool = (tool == "LK_InsertActions" or tool == "LK_KeyTools")
	end
	-- *****************
	-- *** Layers:   ***
	-- *****************
	FO_Utilities:Divider(layout, "Layers")
	layout:PushH(LM.GUI.ALIGN_CENTER, 2)
	-- * Include Child Layers:
	self.ChildLayersCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/child_layers", "Include Child Layers", true, self.TOGGLE_CHILD_LAYERS, true)
	layout:AddChild(self.ChildLayersCheckbox)
	-- * Visible Layers Only:
	self.VisibleLayersOnlyCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_visible_layers_only", "Visible Layers Only (Ignores Invisible Layers)", true, self.TOGGLE_VISIBLE_LAYERS_ONLY, true)
	layout:AddChild(self.VisibleLayersOnlyCheckbox)
	-- * Selected Layers Only:
	self.SelectedLayersOnlyCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_selected_layers_only", "Selected Layers Only (Ignores Unselected Layers)", true, self.TOGGLE_SELECTED_LAYERS_ONLY, true)
	layout:AddChild(self.SelectedLayersOnlyCheckbox)
	-- * Selected Layers Only:
	self.TimelineVisibleLayersOnlyCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_timeline_visible_only", "Timeline Visible Layers Only (Ignores Layers that are not Visible on the Timeline)", true, self.TOGGLE_TIMELINE_VISIBLE_LAYERS_ONLY, true)
	layout:AddChild(self.TimelineVisibleLayersOnlyCheckbox)
	-- * Anim-tagged Layers Only:
	self.AnimTaggedLayersOnlyCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_anim_tagged_only", "'anim' Tagged Layers Only (Ignores Layers that are not tagged with 'anim')", true, self.TOGGLE_ANIM_TAGGED_LAYERS_ONLY, true)
	layout:AddChild(self.AnimTaggedLayersOnlyCheckbox)
	-- * FilterLayerExpressions:
	self.filterOutLayersExprCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_filter", "FILTER OUT LAYER EXPRESSIONS", true, self.TOGGLE_FILTER_LAYER_EXPRESSIONS, true)
	--[[ DISABLED, Filter options are probably sufficient and simpler.
	layout:AddChild(self.filterOutLayersExprCheckbox)
	--]]
	layout:Pop()
	-- *****************
	-- *** Channels: ***
	-- *****************
	FO_Utilities:Divider(layout, "Channels")
	layout:PushH(LM.GUI.ALIGN_CENTER, 2)
	
	-- * Layer:
	self.LayerChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_layer_channels", "Layer Channels", true, self.TOGGLE_LAYER_CHANNELS, true)
	layout:AddChild(self.LayerChannelsCheckbox)
	-- * Wind:
	self.WindChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_wind_channels", "Wind Channels", true, self.TOGGLE_WIND_CHANNELS, true)
	layout:AddChild(self.WindChannelsCheckbox)
	-- * Point:
	self.PointChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_point_channels", "Point Channels", true, self.TOGGLE_POINT_CHANNELS, true)
	layout:AddChild(self.PointChannelsCheckbox)
	-- * Selected Points Only:
	self.SelectedPointsOnlyCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_selected_points_only", "Selected Points Only", true, self.TOGGLE_SELECTED_POINTS_ONLY, true)
	layout:AddChild(self.SelectedPointsOnlyCheckbox)
	-- * Bone:
	self.BoneChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_bone_channels", "Bone Channels", true, self.TOGGLE_BONE_CHANNELS, true)
	layout:AddChild(self.BoneChannelsCheckbox)
	-- * Selected Bones Only:
	self.SelectedBonesOnlyCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_selected_bones_only", "Selected Bones Only", true, self.TOGGLE_SELECTED_BONES_ONLY, true)
	layout:AddChild(self.SelectedBonesOnlyCheckbox)
	-- * Shape:
	self.ShapeChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_shape_channels", "Shape Channels", true, self.TOGGLE_SHAPE_CHANNELS, true)
	layout:AddChild(self.ShapeChannelsCheckbox)
	-- * Selected Shapes Only:
	self.SelectedShapesOnlyCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_selected_shapes_only", "Selected Shapes Only", true, self.TOGGLE_SELECTED_SHAPES_ONLY, true)
	layout:AddChild(self.SelectedShapesOnlyCheckbox)
	-- * Switch:
	self.SwitchChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_switch_channels", "Switch Channels", true, self.TOGGLE_SWITCH_CHANNELS, true)
	if not self.tweenTool then	
		layout:AddChild(self.SwitchChannelsCheckbox)
	end
	-- * Particle:
	self.ParticleChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_particle_channels", "Particle Channels", true, self.TOGGLE_PARTICLE_CHANNELS, true)
	layout:AddChild(self.ParticleChannelsCheckbox)
	-- * Layer Order:
	self.LayerOrderChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_layer_order_channels", "Layer Order Channels", true, self.TOGGLE_LAYER_ORDER_CHANNELS, true)
	if not self.tweenTool then
		layout:AddChild(self.LayerOrderChannelsCheckbox)
	end
	-- * Tracking:
	self.TrackingPointChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_tracking_point_channels", "Tracking Point Channels", true, self.TOGGLE_TRACKING_POINT_CHANNELS, true)
	layout:AddChild(self.TrackingPointChannelsCheckbox)
	-- * Audio:
	self.AudioChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_audio_channels", "Audio Channels", true, self.TOGGLE_AUDIO_CHANNELS, true)
	layout:AddChild(self.AudioChannelsCheckbox)
	-- * Layer-Markers:
	self.layerMarkerChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_layer_marker_channels", "Layer Marker Channels", true, self.TOGGLE_LAYER_MARKER_CHANNELS, true)
	if not self.tweenTool and not self.keyTool then
		layout:AddChild(self.layerMarkerChannelsCheckbox)
	end
	-- ************************
	-- *** Global-channels: ***
	-- ************************
	-- * Camera:
	self.documentMarkerChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_document_marker_channels", "Document-Wide Marker Channels", true, self.TOGGLE_DOCUMENT_MARKER_CHANNELS, true)
	-- * Document-Markers:
	self.CameraChannelsCheckbox = LM.GUI.ImageButton("ScriptResources/FO_icons/channels_camera_channels", "Camera Channels", true, self.TOGGLE_CAMERA_CHANNELS, true)
	if not self.keyTool then
		if self.tweenTool then
		end
		layout:AddChild(self.CameraChannelsCheckbox)
		if not self.tweenTool and not self.keyTool then
			layout:AddChild(self.documentMarkerChannelsCheckbox)
		end
	end
	layout:Pop()
end

function FO_Channels:UpdateWidgets(moho)
	-- * Layers:
	self.ChildLayersCheckbox:SetValue(self.includeChildLayers)
	self.VisibleLayersOnlyCheckbox:SetValue(self.visibleLayersOnly)
	self.SelectedLayersOnlyCheckbox:SetValue(self.selectedLayersOnly)
	self.TimelineVisibleLayersOnlyCheckbox:SetValue(self.timelineVisibleLayersOnly)
	self.AnimTaggedLayersOnlyCheckbox:SetValue(self.animTaggedLayersOnly)
	self.filterOutLayersExprCheckbox:SetValue(self.filterOutLayersExpr ~= "")
	self.filterOutLayersExprCheckbox:SetToolTip("Filter out layers by expressions. "..(self.filterOutLayersExpr))
	-- * Channels:
	self.LayerChannelsCheckbox:SetValue(self.layerChannels)
	self.WindChannelsCheckbox:SetValue(self.windChannels)
	self.PointChannelsCheckbox:SetValue(self.pointChannels)
	self.SelectedPointsOnlyCheckbox:SetValue(self.selectedPointsOnly)
	self.BoneChannelsCheckbox:SetValue(self.boneChannels)
	self.SelectedBonesOnlyCheckbox:SetValue(self.selectedBonesOnly)
	self.ShapeChannelsCheckbox:SetValue(self.shapeChannels)
	self.SelectedShapesOnlyCheckbox:SetValue(self.selectedShapesOnly)
	self.SwitchChannelsCheckbox:SetValue(self.switchChannels)
	self.ParticleChannelsCheckbox:SetValue(self.particleChannels)
	self.LayerOrderChannelsCheckbox:SetValue(self.layerOrderChannels)
	self.TrackingPointChannelsCheckbox:SetValue(self.trackingPointChannels)
	self.AudioChannelsCheckbox:SetValue(self.audioChannels)
	self.layerMarkerChannelsCheckbox:SetValue(self.layerMarkerChannels)
	self.CameraChannelsCheckbox:SetValue(self.cameraChannels)
	self.documentMarkerChannelsCheckbox:SetValue(self.documentMarkerChannels)
	-- * Extra-update selection filters:
	self.SelectedPointsOnlyCheckbox:Enable(self.pointChannels)
	self.SelectedBonesOnlyCheckbox:Enable(self.boneChannels)
	self.SelectedShapesOnlyCheckbox:Enable(self.shapeChannels)
	-- * Disable selection filters:
	if not self.pointChannels then
		self.SelectedPointsOnlyCheckbox:SetValue(false)
	end
	if not self.boneChannels then
		self.SelectedBonesOnlyCheckbox:SetValue(false)
	end
	if not self.shapeChannels then
		self.SelectedShapesOnlyCheckbox:SetValue(false)
	end
	-- * Disable regular if selection filters are enabled:
	self.PointChannelsCheckbox:Enable(not self.selectedPointsOnly)
	self.BoneChannelsCheckbox:Enable(not self.selectedBonesOnly)
	self.ShapeChannelsCheckbox:Enable(not self.selectedShapesOnly)
end

function FO_Channels:HandleMessage(moho, view, msg)
	--
	FO_Channels:BruteOffsetFix(moho) -- TODO
	--
	if not (msg >= self.msg_base and msg < self.LAST_MESSAGE) then
		return -- * Otherwise moho:UpdateUI() would always be called which would screw up certain tools like LK_TweenMachine.
	end
	if msg == self.TOGGLE_CHILD_LAYERS then
		self.includeChildLayers = not self.includeChildLayers
	elseif msg == self.TOGGLE_LAYER_CHANNELS then
		self.layerChannels = not self.layerChannels
	elseif msg == self.TOGGLE_WIND_CHANNELS then
		self.windChannels = not self.windChannels
	elseif msg == self.TOGGLE_POINT_CHANNELS then
		self.pointChannels = not self.pointChannels
	elseif msg == self.TOGGLE_SELECTED_POINTS_ONLY then
		self.selectedPointsOnly = not self.selectedPointsOnly
	elseif msg == self.TOGGLE_BONE_CHANNELS then
		self.boneChannels = not self.boneChannels
	elseif msg == self.TOGGLE_SELECTED_BONES_ONLY then
		self.selectedBonesOnly = not self.selectedBonesOnly
	elseif msg == self.TOGGLE_SHAPE_CHANNELS then
		self.shapeChannels = not self.shapeChannels
	elseif msg == self.TOGGLE_SELECTED_SHAPES_ONLY then
		self.selectedShapesOnly = not self.selectedShapesOnly
	elseif msg == self.TOGGLE_SWITCH_CHANNELS then
		self.switchChannels = not self.switchChannels
	elseif msg == self.TOGGLE_PARTICLE_CHANNELS then
		self.particleChannels = not self.particleChannels
	elseif msg == self.TOGGLE_LAYER_ORDER_CHANNELS then
		self.layerOrderChannels = not self.layerOrderChannels
	elseif msg == self.TOGGLE_TRACKING_POINT_CHANNELS then
		self.trackingPointChannels = not self.trackingPointChannels
	elseif msg == self.TOGGLE_AUDIO_CHANNELS then
		self.audioChannels = not self.audioChannels
	elseif msg == self.TOGGLE_LAYER_MARKER_CHANNELS then
		self.layerMarkerChannels = not self.layerMarkerChannels
	elseif msg == self.TOGGLE_CAMERA_CHANNELS then
		self.cameraChannels = not self.cameraChannels
	elseif msg == self.TOGGLE_DOCUMENT_MARKER_CHANNELS then
		self.documentMarkerChannels = not self.documentMarkerChannels
	elseif msg == self.TOGGLE_VISIBLE_LAYERS_ONLY then
		self.visibleLayersOnly = not self.visibleLayersOnly
		if self.visibleLayersOnly then
			self.selectedLayersOnly = false
			self.timelineVisibleLayersOnly = false
			self.animTaggedLayersOnly = false
		end
	elseif msg == self.TOGGLE_SELECTED_LAYERS_ONLY then
		self.selectedLayersOnly = not self.selectedLayersOnly
		if self.selectedLayersOnly then
			self.visibleLayersOnly = false
			self.timelineVisibleLayersOnly = false
			self.animTaggedLayersOnly = false
		end
	elseif msg == self.TOGGLE_TIMELINE_VISIBLE_LAYERS_ONLY then
		self.timelineVisibleLayersOnly = not self.timelineVisibleLayersOnly
		if self.timelineVisibleLayersOnly then
			self.visibleLayersOnly = false
			self.selectedLayersOnly = false
			self.animTaggedLayersOnly = false
		end
	elseif msg == self.TOGGLE_ANIM_TAGGED_LAYERS_ONLY then
		self.animTaggedLayersOnly = not self.animTaggedLayersOnly
		if self.animTaggedLayersOnly then
			self.visibleLayersOnly = false
			self.selectedLayersOnly = false
			self.timelineVisibleLayersOnly = false
		end
	elseif msg == self.TOGGLE_FILTER_LAYER_EXPRESSIONS then
		if self.filterOutLayersExpr ~= "" then
			self.filterOutLayersExpr = ""
		else
			self.filterOutLayersExpr = "YOLO"
		end
	end
	if moho ~= nil then -- * In case this is triggered from a dialog.
		moho:UpdateUI()
	end
end

function FO_Channels:ChannelAsType(moho, channel)
	-- * Cast channel as type:
	local type = channel:ChannelType()
	local chType
	if (type == 3) then
		chType = moho:ChannelAsAnimColor(channel)
	elseif (type == 2) then
		chType = moho:ChannelAsAnimVec2(channel)
	elseif (type == 6) then
		chType = moho:ChannelAsAnimVec3(channel)
	elseif (type == 5) then
		chType = moho:ChannelAsAnimString(channel)
	elseif (type == 4) then
		chType = moho:ChannelAsAnimBool(channel)
	else
		chType = moho:ChannelAsAnimVal(channel)
	end
	return chType
end

function FO_Channels:AreChannelValuesTheSame(moho, channel)
	print("___AreChannelValuesTheSame___")
	local type = channel:ChannelType()
	local chType
	if (type == 3) then
		chType = moho:ChannelAsAnimColor(channel)
	elseif (type == 2) then
		chType = moho:ChannelAsAnimVec2(channel)
	elseif (type == 6) then
		print("6")
		chType = moho:ChannelAsAnimVec3(channel)
		local vec3a = LM.Vector3:new_local()
		vec3a = chType:GetValueByID(1)
		local vec3b = LM.Vector3:new_local()
		vec3b = chType:GetValueByID(2)
		print(vec3a.x.." "..vec3a.y.." "..vec3a.z)
		print(vec3b.x.." "..vec3b.y.." "..vec3b.z)
		if vec3a.x == vec3b.x and vec3a.y == vec3b.y and vec3a.z == vec3b.z then
			print("return true")
			return true
		end
	elseif (type == 5) then
		chType = moho:ChannelAsAnimString(channel)
	elseif (type == 4) then
		chType = moho:ChannelAsAnimBool(channel)
	else
		chType = moho:ChannelAsAnimVal(channel)
	end
	print("return false")
	return false
end

function FO_Channels:PreferredLayers(moho, global)
	global = global or false
	local layers = {}
	-- *
	if global then
		for i = 0, moho.document:CountLayers()-1 do
			local rootLayer = moho.document:Layer(i)
			FO_Channels:AddLayerWithChildren(moho, rootLayer, layers)
		end
	else
		FO_Channels:AddLayerWithChildren(moho, moho.layer, layers)
	end
	return layers
end

function FO_Channels:ChannelsAsTypes(moho, channels)
	-- *
	local channelsAsTypes = {}
	for i, channel in ipairs(channels) do
		local tweenable = true
		-- * Cast channel as type:
		local type = channel:ChannelType()
		local chType
		if (type == 3) then
			chType = moho:ChannelAsAnimColor(channel)
		elseif (type == 2) then
			chType = moho:ChannelAsAnimVec2(channel)
		elseif (type == 6) then
			chType = moho:ChannelAsAnimVec3(channel)
		elseif (type == 5) then
			chType = moho:ChannelAsAnimString(channel)
			tweenable = false
		elseif (type == 4) then
			chType = moho:ChannelAsAnimBool(channel)
		else
			chType = moho:ChannelAsAnimVal(channel)
		end
		-- * Are dimensions split?
		local split = false
		if (type == 2) or (type == 6) then
			split = chType:AreDimensionsSplit()
		end
		-- * In case they are split:
		if split then
			local axes = 1
			if (type == 6) then
				axes = 2
			end
			for l = 0, axes do
				local d = chType:DimensionChannel(l)
				-- * Insert dimension channel instead of regular channel.
				table.insert(channelsAsTypes, d)
			end
		else
			if not (self.tweenTool and not tweenable) then -- * Skip string channels for tweening!
				-- * Insert regular channel.
				table.insert(channelsAsTypes, chType)
			end
		end
	end
	-- *
	return channelsAsTypes
end

function FO_Channels:AddLayerChannels(moho, layer, channels, forceAll)
	if layer:IsBoneType() then
		local boneLayer = moho:LayerAsBone(layer)
		local skel = boneLayer:Skeleton()
		if self.boneChannels then
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if (not bone.fHidden and (not self.selectedBonesOnly or bone.fSelected)) or forceAll then
					-- * Up to AS 6.0
					table.insert(channels, bone.fAnimAngle)
					table.insert(channels, bone.fAnimPos)
					table.insert(channels, bone.fAnimScale)
					table.insert(channels, bone.fIKLock)
					table.insert(channels, bone.fIKParentTarget)
					table.insert(channels, bone.fIKGlobalAngle)
					table.insert(channels, bone.fBoneDynamics)
					-- * AS 7.0
					table.insert(channels, bone.fPhysicsMotorSpeed)
					-- * AS 8.0:
					-- ???
					-- * AS 9.0:
					-- ???
					-- * AS 10.0:
					table.insert(channels, bone.fTargetBone)
					-- * AS 11.0:
					table.insert(channels, bone.fAnimParent)
					table.insert(channels, bone.fFlipH)
					table.insert(channels, bone.fFlipV)                
				end
			end
			-- * MOHO 13.5 (Vitruvian bones):
			for i = 0, skel:CountGroups() - 1 do
				local group = skel:Group(i)
				table.insert(channels, group.fActiveBone)
			end
		end
		if self.windChannels or forceAll then
			-- * MOHO 13.5 (Wind):
			table.insert(channels, boneLayer.fWindDirection)
			table.insert(channels, boneLayer.fWindStrength)
			table.insert(channels, boneLayer.fWindTurbulentAmplitude)
			table.insert(channels, boneLayer.fWindTurbulentFrequency)
		end
	end
	if self.layerChannels or forceAll then
		-- *
		layer_channels = {
			-- * Up to AS 6.0
			layer.fRotationX,
			layer.fRotationY,
			layer.fRotationZ,
			layer.fTranslation,
			layer.fScale,
			layer.fShear,
			layer.fFlipH,
			layer.fFlipV,
			layer.fVisibility,
			layer.fBlur,
			layer.fAlpha, 
			layer.fLayerShadow,
			layer.fShadowAngle, 
			layer.fShadowOffset,
			layer.fShadowBlur,
			layer.fShadowExpansion,
			layer.fShadowColor,
			layer.fLayerShading,
			layer.fShadingAngle,
			layer.fShadingOffset,
			layer.fShadingBlur,
			layer.fShadingContraction,
			layer.fShadingColor,
			layer.fMotionBlur,
			layer.fMotionBlurFrames,
			layer.fMotionBlurSkip,
			layer.fMotionBlurAlphaStart,
			layer.fMotionBlurAlphaEnd,
			layer.fMotionBlurRadius,
			-- * AS 6.0
			layer.fShadowNoiseAmp,
			layer.fShadowNoiseScale,
			layer.fShadingNoiseAmp,
			layer.fShadingNoiseScale,
			-- * AS 7.0
			layer:PhysicsOptions().fMotorSpeed,
			layer:PhysicsOptions().fForceVector,
			layer.fFollowing,
			layer.fPhysics,
			layer.fPerspectiveShadow,
			layer.fPerspectiveBlur,
			layer.fPerspectiveScale,
			layer.fPerspectiveShear,
			layer.fPerspectiveColor,
			-- * AS 8.0
			layer.fLayerOutline,
			layer.fOutlineWidth,
			layer.fOutlineColor,
			-- * AS 9.0
			-- ???
			-- * AS 10.0
			-- ???
			layer.fLayerColor,
			layer.fLayerColorOn,
			-- * AS 11.0
			-- ???
			-- * MOHO 12.0
			layer.fAmbientOcclusionRadius,
			layer.fMotionBlurExtendedFrames,
			layer.fMotionBlurFramePercentage,
			layer.fMotionBlurSubframes,
			layer.fNoise,
			layer.fPixelation,
			layer.fThreshold
			-- * MOHO 13+ TODO
			}
		for i = 1, #layer_channels do
			layerChannel = layer_channels[i]
			table.insert(channels, layerChannel)
		end
	end
	-- * Add Layer Markers:
	if not self.keyTool then
		if self.layerMarkerChannels or forceAll then
			table.insert(channels, layer.fTimelineMarkers)
		end
	end
	-- * Add additional channels
	if layer:LayerType() == MOHO.LT_VECTOR then
		local mesh = moho:LayerAsVector(layer):Mesh()
		-- * Add point channels
		if self.pointChannels or forceAll then
			for i = 0, mesh:CountPoints()-1 do
				local point = mesh:Point(i)
				if (not point.fHidden and (not self.selectedPointsOnly or point.fSelected)) or forceAll then
					table.insert(channels, point.fAnimPos)
					table.insert(channels, point.fWidth)
					-- * AS 11.0
					table.insert(channels, point.fColor)
					table.insert(channels, point.fColorStrength)
					for j = 0,  point:CountCurves()-1 do
						if curvePointID == nil then
							curvePointID = -1
						end
						curve, curvePointID = point:Curve(j, curvePointID)
						-- * AS 6.1
						if curve.Curvature ~= nil then
							table.insert(channels, curve:Curvature(curvePointID))
						end
					end
				end
			end
			-- * Add curve channels
			for i = 0, mesh:CountCurves() - 1 do
				local curve = mesh:Curve(i)
				-- * Assume curve is selected if at all points is selected (?)
				curve_selected = true
				for j = 0, curve:CountPoints()-1 do
					local point = curve:Point(j)
					if not point.fSelected then
						curve_selected = false
					end
				end
				-- * AS 7.0
				if curve.fStartPercent ~= nil then
					table.insert(channels, curve.fStartPercent)
					table.insert(channels, curve.fEndPercent)
				end
			end
		end
		-- * Add shape color and effect transform channels
		if self.shapeChannels or forceAll then
			for i = 0, mesh:CountShapes() - 1 do
				local shape = mesh:Shape(i)  
				if (not shape.fHidden and (not self.selectedShapesOnly or shape.fSelected)) or forceAll then
					if shape.fEffectScale ~= nil then
						table.insert(channels, shape.fEffectScale)
						table.insert(channels, shape.fEffectRotation)
						table.insert(channels, shape.fEffectOffset)
					end
					local style = shape.fMyStyle
					table.insert(channels, style.fFillCol)
					table.insert(channels, style.fLineCol)
					-- * Add extra shape channels that are only available in ver 7.0 and above
					if shape.f3DThickness ~= nil then
						table.insert(channels, shape.f3DThickness)
					end
				end
			end
		end
	end
	-- * Switch channels:
	if self.switchChannels or forceAll then
		if layer:LayerType() == MOHO.LT_SWITCH then
			-- * Add switch channel
			groupLayer = moho:LayerAsSwitch(layer)
			table.insert(channels, groupLayer:SwitchValues())
		end
	end
	-- * Particle channels:
	if self.particleChannels or forceAll then
		if layer:LayerType() == MOHO.LT_PARTICLE then
			-- * Add particle channel
			groupLayer = moho:LayerAsParticle(layer)
			table.insert(channels, groupLayer:RunningTrack())
		end
	end
	-- * Layer order channel:
	if self.layerOrderChannels or forceAll then
		if layer:IsGroupType() then
			-- * Add layer order channel
			groupLayer = moho:LayerAsGroup(layer)
			if groupLayer.GetLayerOrdering ~= nil then
				table.insert(channels, groupLayer:GetLayerOrdering())
			end
		end
	end
	-- * Tracking channel:
	if self.trackingPointChannels or forceAll then
		if layer:LayerType() == MOHO.LT_IMAGE then
			imageLayer = moho:LayerAsImage(layer)
			if imageLayer.IsMovieLayer ~= nil and imageLayer:IsMovieLayer() then
				-- Add tracking point channels
				-- NB Tracking points only available in AnimeStudio 6.0 and above
				for i = 0, imageLayer:CountTrackingPoints()-1 do
					trackingPoint = imageLayer:GetTrackingPoint(i)
					table.insert(channels, trackingPoint.fAnimPos)
				end
			end
		end
	end
	-- * Audio channels:
	if self.audioChannels or forceAll then
		if layer:IsAudioType() then
			local audioLayer = moho:LayerAsAudio(layer)
			if audioLayer ~= nil then
				table.insert(channels, audioLayer.fAudioLevel)
				table.insert(channels, audioLayer.fJumpToFrame)
			end
		end
	end

	-- TODO TODO anders error tweenmachine
	-- -- * Jump To Frame channel
	-- if layer:LayerDuration() > 0 then
	-- 	local mediaLayer = moho:LayerAsAudio(layer)
	-- 	if mediaLayer == nil then
	-- 		mediaLayer = moho:LayerAsImage(layer)
	-- 	end
	-- 	if mediaLayer ~= nil then
	-- 		table.insert(channels, mediaLayer.fJumpToFrame)
	-- 	end
	-- end

	return channels
end

function FO_Channels:GlobalChannels(moho)
	local doc = moho.document
	-- * NB doc.fCameraTrack has to be last as it seems to stuff up the Lua table 
	-- * Maybe it's because it's of type AnimVec3
	local globalChannels = {
		-- * Camera channels:
		doc.fCameraZoom, 
		doc.fCameraRoll, 
		doc.fCameraPanTilt, 
		doc.fCameraTrack,
		-- * Document markers AS 10.1:
		doc.fTimelineMarkers
	}
	return globalChannels
end

function FO_Channels:AddGlobalChannels(moho, channels)
	local doc = moho.document
	if self.cameraChannels then
		table.insert(channels, doc.fCameraZoom)
		table.insert(channels, doc.fCameraRoll)
		table.insert(channels, doc.fCameraPanTilt)
		table.insert(channels, doc.fCameraTrack)
	end
	if self.documentMarkerChannels then
		table.insert(channels, doc.fTimelineMarkers)
	end
end

function FO_Channels:AddLayerWithChildren(moho, layer, layers) -- * Name of function is a bit confusing, because children are only added if that option is true
	-- *
	local dontAdd = false -- * For some filters we still might want to include their children.
	-- * Negate layer offset:
	if layer:TimingOffset() ~= 0 then
		if layer:IsAudioType() or (moho:LayerAsImage(layer) and moho:LayerAsImage(layer):IsMovieLayer()) or (moho:LayerAsImage(layer) and moho:LayerAsImage(layer):IsImageSequenceLayer()) then
			-- dontAdd = true
			if layer:AnimDuration() > 0 then
				print("Warning: Skipped '"..layer:Name().."', because it is an offsetted audiovisual element. So any key in this layer is still in the same location. Animate group instead if you want to use this tool.")
			end
			local audioLayer = moho:LayerAsImage(layer)
			local timingChannel = audioLayer.fJumpToFrame
			local offset = layer:TimingOffset() * -1 + 1
			-- * Change start frame:
			-- timingChannel:SetValue(0, true)
			-- timingChannel:SetValue(offset, true)
			timingChannel:SetValue(1, true)
			-- * Visibility:
			layer.fVisibility:SetValue(1, true)
			layer.fVisibility:SetValue(0, false)
			-- * Add marker:
			layer.fTimelineMarkers:SetValue(1, layer:Name())
			local markerInterp = MOHO.InterpSetting:new_local()
			markerInterp.hold = layer:LayerDuration()
			markerInterp.tags = layer:LabelColor()
			layer.fTimelineMarkers:SetKeyInterp(1, markerInterp)
		end
		if not dontAdd then
		-- else
			moho.document:SetDirty()
			moho.document:PrepUndo(layer)
			local offset = layer:TimingOffset()
			layer:SetTimingOffset(0)
			local forceAll = true -- * Because we want to fix ALL channels when negating layer offset.
			LK_NudgeKeys:LayerShift(1, moho, offset*-1, layer, forceAll)
			FO_Utilities:Alert(layer:Name().." was offset by "..offset.." but it's been reset to 0 and keys have been shifted "..(offset*-1).." frames instead!")
		end
	end
	-- * Visibility filter:
	if self.visibleLayersOnly and not layer:IsVisible() then
		return -- * We don't want to check this layer's children, because they are invisible too.
	end
	-- * Selection filter:
	if self.selectedLayersOnly and not layer:SecondarySelection() then
		dontAdd = true
	end
	-- * Timeline visibility filter:
	if self.timelineVisibleLayersOnly and not (layer:IsShownOnTimeline() or (layer == moho.layer)) then
		dontAdd = true
	end
	if self.animTaggedLayersOnly and not FO_Utilities:LayerHasTag(layer, FO_Utilities.animTag) then
		dontAdd = true
	end
	-- * Check whether layer is to be filtered out:
	if self.filterOutLayersExpr ~= "" and string.find(layer:Name(), self.filterOutLayersExpr) then
		print (layer:Name().." filtered")
		dontAdd = true
	end
	-- * Add them:
	if not dontAdd then
		table.insert(layers, layer)
	end
	-- *
	if self.includeChildLayers then
		if layer:IsGroupType() then
			layer = moho:LayerAsGroup(layer)
			for i = 0, layer:CountLayers() - 1 do
				self:AddLayerWithChildren(moho, layer:Layer(i), layers)
			end
		end
	end
end

-- -- **************************************************
-- -- Function name is weird, being used to go to prev/next keyframe
-- -- **************************************************
-- -- TODO use findkey() instead, but that returns int or nil instead of bool
-- function FO_Channels:AllChannelsHasKey(channels, global_channels, startFrame, endFrame, moho)
-- 	print ("AllChannelsHasKey")
-- 	-- Check whether any channels have keyframe in the given frame range
-- 	local doc
-- 	local found_key = false
-- 	local incr
-- 	local layer = moho.layer
-- 	local timing_offset
-- 	-- * Forwards or backwards:
-- 	if endFrame > startFrame then
-- 		incr = 1
-- 	else
-- 		incr = -1
-- 	end
-- 	-- * Offset:
-- 	if layer.TotalTimingOffset ~= nil then
-- 		timing_offset = layer:TotalTimingOffset()
-- 	else
-- 	timing_offset = 0
-- 	end
-- 	-- * Go through next/previous frames and stop when a keyframe is found
-- 	for frame = startFrame, endFrame, incr do
-- 		for i = 1, #channels do
-- 			local channel = channels[i]
-- 			if channel.HasKey ~= nil and channel:HasKey(frame) then
-- 				found_key = true
-- 				break
-- 			end
-- 		end
-- 		if found_key == false and global_channels ~= nil then
-- 			for i = 1, #global_channels do
-- 				local channel = global_channels[i]
-- 				if channel.HasKey ~= nil and channel:HasKey(frame) then
-- 					found_key = true
-- 					break
-- 				end
-- 			end
-- 		end
-- 		if found_key then
-- 			moho:SetCurFrame(frame - timing_offset)
-- 			-- * Set it TWICE because of bone dynamics:
-- 			moho:SetCurFrame(frame - timing_offset)
-- 			break
-- 		end
-- 	end
-- 	return found_key
-- end

-- * TODO FIX UP
function FO_Channels:FindKey(moho, channels, startFrame, endFrame)
	-- Check whether any channels have keyframe in the given frame range
	local doc
	local found_key = false
	
	
	local timing_offset
	-- * Forwards or backwards:
	local incr
	if endFrame > startFrame then
		incr = 1
	else
		incr = -1
	end
	-- * Offset:
	local layer = moho.layer
	if layer.TotalTimingOffset ~= nil then
		timing_offset = layer:TotalTimingOffset()
	else
		timing_offset = 0
	end
	-- * Go through next/previous frames and stop when a keyframe is found
	for frame = startFrame, endFrame, incr do
		-- print (startFrame.." "..endFrame.." "..incr.." "..frame)
		for i = 1, #channels do
			local channel = channels[i]
			if channel.HasKey ~= nil and channel:HasKey(frame) then
				found_key = true
				break
			end
		end
		if found_key then
			local keyFoundAt = frame - timing_offset
			return keyFoundAt
		end
	end
	return nil
end

-- **************************************************
-- Go to previous/next key:
-- **************************************************
function FO_Channels:GoToPrevNextKeyFrame(moho, previous)
	local layers = FO_Channels:PreferredLayers(moho)
	local channels = {}
	for i = 1, #layers do
		FO_Channels:AddLayerChannels(moho, layers[i], channels)
	end
	FO_Channels:AddGlobalChannels(moho, channels)
	local current_frame    
	if moho.layerFrame ~= nil then
		current_frame = moho.layerFrame
	else
		current_frame = moho.frame
	end
	local startFrame
	local endFrame
	if previous then
		-- * Backwards:
		startFrame = current_frame-1
		endFrame = 0
	else
		-- * Forwards:
		local bigStep = 20
		startFrame = current_frame+1
		endFrame = current_frame+bigStep
	end
	-- * Do it in two stages as running AnimDuration takes a while
	local found_key = FO_Channels:FindKey(moho, channels, startFrame, endFrame)
	if found_key then
		moho:SetCurFrame(found_key+10) -- * Dynamics bug
		moho:SetCurFrame(found_key)
	else
		-- * Second stage (only when looking forwards):
		local anim_duration = moho.document:AnimDuration()
		found_key = FO_Channels:FindKey(moho, channels, endFrame+1, anim_duration)
		if found_key then
			moho:SetCurFrame(found_key+10) -- * Dynamics bug
			moho:SetCurFrame(found_key)
		end
	end
	moho:UpdateUI()
	-- MOHO.Redraw()
end

function FO_Channels:BruteOffsetFix(moho) -- * TODO
	for i = 0, moho.document:CountLayers() - 1 do
		local layer = moho.document:Layer(i)
		local offset = layer:TimingOffset()
		if offset ~= 0 then
			layer:SetTimingOffset(0)
			local forceAll = true -- * Because we want to fix ALL channels when negating layer offset.
			LK_NudgeKeys:LayerShift(1, moho, offset*-1, layer, forceAll)
			FO_Utilities:Alert(layer:Name().." was offset by "..offset.." but it's been reset to 0 and keys have been shifted "..(offset*-1).." frames instead!")
		end
	end
end

FO_Channels
Unlisted

Author: Lukas View Script
Script type: Utility

Uploaded: May 15 2023, 07:31

Last modified: Sep 05 2023, 12:57

Channels Utility so multiple tools can use the same channel-filter in their toolbars
Channels Utility so multiple tools can use the same channel-filter in their toolbars
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 742