Image
--*************************************************
-- Provide Moho with the name of this script object
--*************************************************

ScriptName = "LK_ColorBones"

--*************************************************
-- General information about this script
--*************************************************

LK_ColorBones = {}

function LK_ColorBones:Name()
	return "Color Bones Window"
end

function LK_ColorBones:Version()
	return '0.0'
end

function LK_ColorBones:UILabel()
	return "Color Bones Window"
end

function LK_ColorBones:Creator()
	return 'Lukas Krepel'
end

function LK_ColorBones:Description()
	return "Color Bones Window"
end

function LK_ColorBones:ColorizeIcon()
   return true
end

--*************************************************
-- Is Relevant / Is Enabled
--*************************************************

function LK_ColorBones:IsRelevant(moho)
	return true
end

function LK_ColorBones:IsEnabled(moho)
	return true
end

LK_ColorBones.dynamicMode = true
LK_ColorBones.mode = 1 -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect

LK_ColorBones.shortcutBoneColor = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "--10", "--11" }

function LK_ColorBones:OnKeyDown(moho, keyEvent)
	for i = 1, #self.shortcutBoneColor do
		if self.shortcutBoneColor[i] == keyEvent.key then
			if not keyEvent.altKey then
				LK_ColorBonesDialog:HandleMessage(LK_ColorBonesDialog.COLOR_BONES + i - 1) -- NO MODIFIERS
			else
				LK_ColorBonesDialog:HandleMessage(LK_ColorBonesDialog.COLOR_BONES_ALT + i - 1) -- ALT
			end
		end
	end
	--?
end

--*************************************************
-- Panel
--*************************************************

LK_ColorBonesDialog = {}

LK_ColorBonesDialog.modeTooltip = {
	"Show/Hide Bones (<alt> to Expose)",
	"Set Bone Color (<alt> to Select)",
	"Select Bones (<alt> to add)"
}

LK_ColorBonesDialog.ALL_BONES 		= MOHO.MSG_BASE
LK_ColorBonesDialog.DIAL_BONES		= MOHO.MSG_BASE + 1
LK_ColorBonesDialog.DYNAMIC_MODE		= MOHO.MSG_BASE + 2
LK_ColorBonesDialog.SET_MODE		 	= MOHO.MSG_BASE + 3 -- (3 t/m mode count)
LK_ColorBonesDialog.COLOR_BONES		= MOHO.MSG_BASE + 100 -- (100 = 0 = Plain t/m 111 = 11 = Coral)
LK_ColorBonesDialog.COLOR_BONES_ALT	= MOHO.MSG_BASE + 112 -- (112 = 0 = Plain t/m 123 = 11 = Coral)

function LK_ColorBonesUpdateDialog(moho)
	if LK_ColorBones.dialog ~= nil then
		LK_ColorBones.dialog:UpdateWidgets()
	end
end

table.insert(MOHO.UpdateTable, LK_ColorBonesUpdateDialog)

--*************************************************
-- Preferences
-- TODO SavePrefs doesnt seem to work
--*************************************************
function LK_ColorBones:LoadPrefs(prefs)
	LK_ColorBones.mode = prefs:GetInt("LK_ColorBones.mode", 1)
	LK_ColorBones.dynamicMode = prefs:GetBool("LK_ColorBones.dynamicMode", false)
end

function LK_ColorBones:SavePrefs(prefs) -- TODO Have not been able to get this to work:
	prefs:SetInt("LK_ColorBones.mode", LK_ColorBones.mode)
	prefs:SetBool("LK_ColorBones.dynamicMode", LK_ColorBones.dynamicMode)
end

function LK_ColorBones:ResetPrefs(prefs)
	LK_ColorBones.mode = 1
	LK_ColorBones.dynamicMode = true
end

--*************************************************
-- New dialog (essentially DoLayout)
--*************************************************

function LK_ColorBonesDialog:new(moho)
	local d = LM.GUI.SimpleDialog("Color Bones", LK_ColorBonesDialog)
	local layout = d:GetLayout()
	layout:PushH()
		d.skelButtons = {}
		-- all bones button
		d.allBonesButton = LM.GUI.ImageButton("ScriptResources/FO_icons/color_All", "All Bones", true, self.ALL_BONES, true)
		layout:AddChild(d.allBonesButton)
		-- dials button
		d.boneDialsButton = LM.GUI.ImageButton("ScriptResources/FO_icons/dials", "Bone-Dials", true, self.DIAL_BONES, true)
		table.insert(d.skelButtons, d.boneDialsButton)
		layout:AddChild(d.boneDialsButton)
		--
		d.colorButtons = {}
		for i = 0, #FO_Utilities.colorNames do
			local icon = "ScriptResources/FO_icons/color_"..FO_Utilities.colorNames[i]

			local numberIcons = false
			if MohoMode ~= nil then
				if not MohoMode.vanilla then
					numberIcons = true
				end
			end
			if i <= 9 and numberIcons then
				icon = icon.."_number"
			end
			d.colButton = LM.GUI.ImageButton(icon, nil, true, self.COLOR_BONES + i, false)
			d.colButton:SetAlternateMessage(self.COLOR_BONES_ALT + i)
			table.insert(d.colorButtons, d.colButton)
		end
		-- Show Plain bones:
		local buttonColor = 0
		layout:PushH(LM.GUI.ALIGN_CENTER, 0)
			table.insert(d.skelButtons, d.colorButtons[1])
			layout:AddChild(d.colorButtons[1])
			-- Show color bones:
			local reverse = FO_Utilities.reverseBoneColorButtons
			local start = 2
			local stop = #d.colorButtons
			local increment = 1
			if reverse then
				start, stop = stop, start
				increment = -1
			end
			for i = start, stop, increment do --todo start/end/incr fixen
				local buttonColor = i - 1
				table.insert(d.skelButtons, d.colorButtons[i])
				layout:AddChild(d.colorButtons[i])
			end
		layout:Pop()
	
	d.selectModeMenu = LM.GUI.Menu("Mode")
	d.modeDropdown_popup = LM.GUI.PopupMenu(200, false)
	d.modeDropdown_popup:SetMenu(d.selectModeMenu)
	layout:AddChild(d.modeDropdown_popup)

	d.dynamicModeCheckbox = LM.GUI.CheckBox("Dynamic", self.DYNAMIC_MODE)
	layout:AddChild(d.dynamicModeCheckbox)

	layout:Pop()
	return d
end

--*************************************************
-- Update dialog
--*************************************************
function LK_ColorBonesDialog:UpdateWidgets()
	local helper = MOHO.ScriptInterfaceHelper:new_local()
	local moho = helper:MohoObject()
	local frame = moho.frame
	local layer = moho.document:GetSelectedLayer(1)
	local skel = moho:Skeleton()
	if skel == nil then
		if moho:LayerAsBone(layer) then
			skel = moho:LayerAsBone(layer):Skeleton()
		else
			skel = layer:ControllingSkeleton()
		end
	end
	self:UpdateMode(moho)

	-- Select mode menu
	self.selectModeMenu:RemoveAllItems()
	self.selectModeMenu = LM.GUI.Menu(LK_ColorBonesDialog.modeTooltip[LK_ColorBones.mode])
	local i
	for i = 1, #LK_ColorBonesDialog.modeTooltip do
		local modeName = LK_ColorBonesDialog.modeTooltip[i]
		self.selectModeMenu:AddItem(modeName, 0, (self.SET_MODE + i))
		-- Fix checkmarks per mode
		if (LK_ColorBones.mode == i) then
			self.selectModeMenu:SetChecked((self.SET_MODE + i), true)
		else
			self.selectModeMenu:SetChecked((self.SET_MODE + i), false)
		end
	end

	self.dynamicModeCheckbox:SetValue(LK_ColorBones.dynamicMode)

	self.modeDropdown_popup:SetMenu(self.selectModeMenu)
	self.modeDropdown_popup:Redraw()



	if skel ~= nil then
		-- ANALYZE BONES
		local visibleBones = {}
		local hiddenBones = {}
		local visibleDials = {}
		local hiddenDials = {}
		local unselectedColorBones = {}
		local allDialsSelected = true
		for i = 0, skel:CountBones() - 1 do
			local bone = skel:Bone(i)
			local boneColor = bone:Tags()
			if not bone.fShy then
				if bone.fHidden then
					table.insert(hiddenBones, boneColor)
				elseif not bone.fHidden then
					table.insert(visibleBones, boneColor)
					if not bone.fSelected then
						table.insert(unselectedColorBones, boneColor)
					end
				end
				-- Dials
				if bone.fConstraints and bone:IsLabelShowing() then
					if bone.fHidden then
						table.insert(hiddenDials, boneColor)
					elseif not bone.fHidden then
						table.insert(visibleDials, boneColor)
						if not bone.fSelected then
							allDialsSelected = false
						end
					end
				end
			end
		end
		--
		if LK_ColorBones.mode == 1 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			-- Grey out colors that are not in use.
			-- Highlight visible colors
			for i, button in ipairs(self.colorButtons) do
				local buttonColor = i-1
				if table.contains(hiddenBones, buttonColor) then
					button:Enable(true)
					button:SetValue(false)
				elseif table.contains(visibleBones, buttonColor) then
					button:Enable(true)
					button:SetValue(true)
				else
					button:Enable(false)
					button:SetValue(false)
				end
			end
			if table.contains(hiddenBones, 0) or table.contains(hiddenBones, 1) or table.contains(hiddenBones, 2) or table.contains(hiddenBones, 3) or table.contains(hiddenBones, 4) or table.contains(hiddenBones, 5) or table.contains(hiddenBones, 6) or  table.contains(hiddenBones, 7) or table.contains(hiddenBones, 8) or table.contains(hiddenBones, 9) or table.contains(hiddenBones, 10) or table.contains(hiddenBones, 11) then
				self.allBonesButton:Enable(true)
				self.allBonesButton:SetValue(false)
			elseif table.contains(visibleBones, 0) or table.contains(visibleBones, 1) or table.contains(visibleBones, 2) or table.contains(visibleBones, 3) or table.contains(visibleBones, 4) or table.contains(visibleBones, 5) or table.contains(visibleBones, 6) or table.contains(visibleBones, 7) or table.contains(visibleBones, 8) or table.contains(visibleBones, 9) or table.contains(visibleBones, 10) or table.contains(visibleBones, 11) then
				self.allBonesButton:Enable(true)
				self.allBonesButton:SetValue(true)
			else
				self.allBonesButton:Enable(false)
				self.allBonesButton:SetValue(false)
			end
			if #hiddenDials > 0 then
				self.boneDialsButton:Enable(true)
				self.boneDialsButton:SetValue(false)
				self.hiddenDials = true
			elseif #visibleDials > 0 and #hiddenDials == 0 then
				self.boneDialsButton:Enable(true)
				self.boneDialsButton:SetValue(true)
				self.hiddenDials = false
			else
				self.boneDialsButton:Enable(false)
				self.boneDialsButton:SetValue(false)
			end
		elseif LK_ColorBones.mode == 2 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			local anySelected = skel:SelectedBoneID() > 0
			for i, button in ipairs(self.colorButtons) do
				button:Enable(true)
				button:SetValue(false)
			end
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if (bone.fSelected) then
					local tags = bone:Tags()
					for i, button in ipairs(self.colorButtons) do
						local buttonColor = i - 1
						button:Enable(true)
						if tags == buttonColor then
							button:SetValue(true)
						end
					end
				end
			end
			--
			self.allBonesButton:Enable(true) -- always true, for alt functionality
			self.allBonesButton:SetValue(false) -- ?
			self.boneDialsButton:Enable(true) -- always true, for alt functionality
			self.boneDialsButton:SetValue(false) -- ?
		elseif LK_ColorBones.mode == 3 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			-- grey out colors that are not in use
			-- highlight buttons that of which all visible all selected
			local allHighlight = true
			local dialHighlight = true
			for i, button in ipairs(self.colorButtons) do
				local buttonColor = i-1
				if table.contains(visibleBones, buttonColor) then
					button:Enable(true)
					if table.contains(unselectedColorBones, buttonColor) then
						button:SetValue(false)
						allHighlight = false
					else
						button:SetValue(true)
					end
				else
					button:Enable(false)
					button:SetValue(false)
				end
			end
			--
			self.allBonesButton:Enable(#visibleBones > 0)
			self.allBonesButton:SetValue(allHighlight)
			self.boneDialsButton:Enable(#visibleDials > 0)
			self.boneDialsButton:SetValue(allDialsSelected)
		end
	else -- skel==nil
		-- Disable all buttons
		for i, button in ipairs(self.colorButtons) do
			local buttonColor = i-1
			button:Enable(false)
			button:SetValue(false)
		end
		self.allBonesButton:Enable(false)
		self.allBonesButton:SetValue(false)
		self.boneDialsButton:Enable(false)
		self.boneDialsButton:SetValue(false)
	end
	-- DELETE HELPER
	helper:delete()
end

function LK_ColorBonesDialog:UpdateMode(moho)
	if not LK_ColorBones.dynamicMode then return end
	local tool = moho:CurrentTool()
	local frame = moho.frame + moho.layer:TotalTimingOffset()
	LK_ColorBones.mode = 1 -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
	if tool == "LM_AddBone" or tool == "LK_BoneSettings" or (tool == "LM_SelectBone" and frame == 0) then
		LK_ColorBones.mode = 2
	elseif tool == "LM_SelectBone" then
		LK_ColorBones.mode = 3
	end
end

--*************************************************
-- Handle dialog messages
--*************************************************
function LK_ColorBonesDialog:HandleMessage(msg)
	local helper = MOHO.ScriptInterfaceHelper:new_local()
	local moho = helper:MohoObject()
	self:UpdateMode(moho)
	local layer = moho.layer
	local action = layer:CurrentAction()
	local skel = nil
	if moho:LayerAsBone(layer) then
		skel = moho:LayerAsBone(layer):Skeleton()
	else
		skel = layer:ControllingSkeleton()
	end
	if skel == nil then
		print("WHAT? skel == nil...stop, this should never happen")
		return
	end
	--
	if msg == self.DYNAMIC_MODE then
		LK_ColorBones.dynamicMode = not LK_ColorBones.dynamicMode
	elseif msg >= self.SET_MODE and msg <= self.SET_MODE + #LK_ColorBonesDialog.modeTooltip then -- TODO LIMIT
		LK_ColorBones.mode = msg - self.SET_MODE
		LK_ColorBones.dynamicMode = false
	elseif msg == self.ALL_BONES then
		if LK_ColorBones.mode == 1 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			local button = self.allBonesButton
			button:SetValue(not(button:Value()))
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if not bone.fShy then
					bone.fHidden = button:Value()
				elseif bone.fShy and layer:IsSmartBoneAction(action) and boneColor ~= 1 then
					bone.fHidden = button:Value()
				end
			end
		elseif LK_ColorBones.mode == 2 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			-- N/A
		elseif LK_ColorBones.mode == 3 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				bone.fSelected = true
			end
		end
	elseif msg == self.DIAL_BONES then
		if LK_ColorBones.mode == 1 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			for i = 0, skel:CountBones()-1 do
				local bone = skel:Bone(i)
				if not bone.fShy and bone.fConstraints and bone:IsLabelShowing() then
					bone.fHidden = not self.hiddenDials
				end
			end
		elseif LK_ColorBones.mode == 2 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			-- N/A
		elseif LK_ColorBones.mode == 3 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if not bone.fShy and bone.fConstraints and bone:IsLabelShowing() then
					bone.fSelected = true
				end
			end
		end
	elseif msg >= self.COLOR_BONES and msg <= self.COLOR_BONES + 11 then
		-- COLOR BONE ACTION 1
		local buttonColor = msg - self.COLOR_BONES
		if LK_ColorBones.mode == 1 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			local doHide = true
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				local boneColor = bone:Tags()
				if boneColor == buttonColor and bone.fHidden and not bone.fShy then
					doHide = false
					break
				end
			end
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				local boneColor = bone:Tags()
				if boneColor == buttonColor and not bone.fShy then
					bone.fHidden = doHide
				elseif boneColor == buttonColor and bone.fShy and layer:IsSmartBoneAction(action) and boneColor ~= 1 then
					bone.fHidden = doHide
				end
			end
		elseif LK_ColorBones.mode == 2 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			moho.document:PrepUndo(layer, true) -- TODO are we sure this doesn't make Moho crash sometimes?
			moho.document:SetDirty() -- TODO are we sure this doesn't make Moho crash sometimes?
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if bone.fSelected then
					bone:SetTags(buttonColor)
				end
			end
			--layer:UpdateCurFrame(true)
			--FO_Utilities:PaintKeys(moho)
		elseif LK_ColorBones.mode == 3 then -- 1=Toggle/Expose, 2=Set/Select, 3=Select/AddSelect
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				local boneColor = bone:Tags()
				if boneColor == buttonColor and not bone.fShy then
					bone.fSelected = true
				else
					bone.fSelected = false
				end
			end
		end
	elseif msg >= self.COLOR_BONES_ALT and msg <= self.COLOR_BONES_ALT + 11 then
		-- COLOR BONE ALTERNATE ACTION
		local buttonColor = msg - self.COLOR_BONES_ALT
		if LK_ColorBones.mode == 1 then -- 0=Toggle/Expose, 1=Set/Select,2=Select/AddSelect
			-- EXPOSE COLOR (and toggle back)
			FO_Utilities:ToggleExposeColorBones(layer, skel, buttonColor)
		elseif LK_ColorBones.mode == 2 then -- 0=Toggle/Expose, 1=Set/Select,2=Select/AddSelect
			-- SET COLOR SELECTION (Double code, move to function TODO)
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				local boneColor = bone:Tags()
				if boneColor == buttonColor and not bone.fShy then
					bone.fSelected = true
				else
					bone.fSelected = false
				end
			end
		elseif LK_ColorBones.mode == 3 then -- 0=Toggle/Expose, 1=Set/Select,2=Select/AddSelect
			-- ADD COLOR TO SELECTION
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				local boneColor = bone:Tags()
				if boneColor == buttonColor and not bone.fShy then
					bone.fSelected = true
				end
			end
		end
	end
	MOHO.Redraw() -- Redraws viewport so we can see what bones are toggled.
	moho:UpdateUI() -- Redraws timeline channels so we can see keys for toggled bones (dis)appearing.
	--
	helper:delete() -- Currently it gets deleted at the start of the function, and UpdateUI seems to work regardless.
end

--*************************************************
-- Delete dialog
--*************************************************
function LK_ColorBonesDialog:OnOK()
	LK_ColorBones.dialog = nil
end

--*************************************************
-- Create dialog
--*************************************************
function LK_ColorBones:Run(moho)
	if self.dialog == nil then
		self.dialog = LK_ColorBonesDialog:new()
		if self.dialog then
			if (self.dialog:DoModeless() == LM.GUI.MSG_CANCEL) then
				return false
			end
		end
	end
end

Icon
Color Bones
Listed

Author: Lukas View Script
Script type: Button/Menu

Uploaded: Sep 10 2024, 07:54

Last modified: Sep 13 2024, 04:00

Script Version: 0.0

Color Bones Window
Image
Modal window handle Color Bones. Alpha version. Please send me a message when encountering bugs.

Functionality is dynamic (or static if you choose to disable dynamic mode), three modes are available and change depending on the current tool and also if you are on fame 0 or not:

- Default → Show/Hide Bones (ALT to Expose)
- Add Bone (and Select Bone at frame 0) → Set Bone Color (ALT to Select)
- Select Bone → Select Bones (ALT to Add)

Shorcuts are disabled by default because number keys are reserved for the default Moho tools, but you can enable them in the code:
For shortcuts [1,2,3,4,5,6,7,8,9,0]  change:
"local numberIcons = false" → "local numberIcons = true"
And you'll need to edit your other tools and add one line, for example:

function LM_AddBone:OnKeyDown(moho, keyEvent)
    LK_BoneSettings:OnKeyDown(moho, keyEvent)
    [...]

Installation Options:

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: 200