Well, I've got it working. Thanks to the wonders of copy and paste, I was able to make the first version in less than half an hour
All I did was make a replacement version of the lm_scale_points.lua script that scales the line together with the points. Here's the script for those of you who want to try it. All you have to do is replace the contents of the lm_scale_points.lua script with this. Made for 5.6, so no idea how it works for higher versions.
Note that I didn't add a button to switch the line scaling on and off. Also, I haven't commented the code in any way, which I know is big no-no, so only use this if you're curious and remember to back up the original lm_scale_points.lua first.
Code: Select all
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************
ScriptName = "LM_ScalePoints"
-- **************************************************
-- General information about this script
-- **************************************************
LM_ScalePoints = {}
LM_ScalePoints.BASE_STR = 2280
function LM_ScalePoints:Name()
return "Scale Points"
end
function LM_ScalePoints:Version()
return "5.0"
end
function LM_ScalePoints:Description()
return MOHO.Localize(self.BASE_STR, "Scale selected points (hold <alt> to preserve volume)")
end
function LM_ScalePoints:Creator()
return "Lost Marble"
end
function LM_ScalePoints:UILabel()
return(MOHO.Localize(self.BASE_STR + 1, "Scale Points"))
end
-- **************************************************
-- Recurring values
-- **************************************************
LM_ScalePoints.scalingDir = -1
LM_ScalePoints.minVec = LM.Vector2:new_local()
LM_ScalePoints.maxVec = LM.Vector2:new_local()
-- **************************************************
-- The guts of this script
-- **************************************************
function LM_ScalePoints:IsEnabled(moho)
if (moho:CountSelectedPoints() > 1) then
return true
end
return false
end
function LM_ScalePoints:OnMouseDown(moho, mouseEvent)
local mesh = moho:Mesh()
if (mesh == nil) then
return
end
mesh:SelectedBounds(self.minVec, self.maxVec)
self.centerVec = (self.minVec + self.maxVec) / 2
-- First step - figure out which scaling handle is being dragged
self.scalingDir = -1
local boxW = (self.maxVec.x - self.minVec.x) / 2
local boxH = (self.maxVec.y - self.minVec.y) / 2
dx = mouseEvent.vec.x - self.centerVec.x
dx = math.abs(dx)
dy = mouseEvent.vec.y - self.centerVec.y
dy = math.abs(dy)
if ((dx > 0.8 * boxW) and (dx < 1.2 * boxW)) then
if ((dy > 0.8 * boxH) and (dy < 1.2 * boxH)) then
self.scalingDir = 2
elseif (dy < 0.2 * boxH) then
self.scalingDir = 0
end
elseif (dx < 0.2 * boxW) then
if ((dy > 0.8 * boxH) and (dy < 1.2 * boxH)) then
self.scalingDir = 1
end
end
if ((self.scalingDir < 0) and (dx > 0.8 * boxW) and (dy > 0.8 * boxH)) then
self.scalingDir = 2
end
if (self.scalingDir < 0) then
return
end
moho.document:PrepUndo(moho.layer)
moho.document:SetDirty()
mesh:PrepMovePoints()
self.selID = -1
self.selList = MOHO.SelectedPointList(mesh)
self.numSel = table.getn(self.selList)
if (self.numSel < 2) then -- work with only the closest selection
-- find the closest point here
self.selID = mesh:ClosestPoint(mouseEvent.startVec)
if (self.selID >= 0) then
self.numSel = 1
mesh:SelectNone()
local pt = mesh:Point(self.selID)
pt.fSelected = true
if (pt.fWidth.value < 0) then
pt.fWidth:SetValue(moho.frame, 0)
end
pt.fTempWidth = pt.fWidth.value
moho:UpdateSelectedChannels()
end
self.selList = MOHO.SelectedPointList(mesh)
self:UpdateWidgets(moho)
end
for i, pt in self.selList do
if (pt.fWidth.value < 0) then
pt.fWidth:SetValue(moho.frame, 0)
end
pt.fTempWidth = pt.fWidth.value
end
mouseEvent.view:DrawMe()
end
function LM_ScalePoints:OnMouseMoved(moho, mouseEvent)
local mesh = moho:Mesh()
if (mesh == nil) then
return
end
if (self.scalingDir < 0) then
return
end
local scaling = LM.Vector2:new_local()
scaling:Set(1, 1)
-- scaling connected to actual drag amount
local v1 = mouseEvent.startVec - self.centerVec
local v2 = mouseEvent.vec - self.centerVec
scaling.x = v2.x / v1.x
scaling.y = v2.y / v1.y
if (self.scalingDir == 0) then
scaling.y = 1
if (mouseEvent.altKey) then
scaling.y = 1 / scaling.x
end
elseif (self.scalingDir == 1) then
scaling.x = 1
if (mouseEvent.altKey) then
scaling.x = 1 / scaling.y
end
else
scaling.x = (scaling.x + scaling.y) / 2
scaling.y = scaling.x
end
mesh:ScalePoints(scaling.x, scaling.y, self.centerVec)
moho:AddPointKeyframe(moho.frame)
local offset = (math.abs(scaling.x) + math.abs(scaling.y))/2
local maxWidth = moho:PixelToDoc(64)
if (self.numSel == 1) then
local pt = mesh:Point(self.selID)
pt.fWidth.value = pt.fTempWidth * offset
pt.fWidth.value = LM.Clamp(pt.fWidth.value, 0, maxWidth)
pt.fWidth:StoreValue()
else
for i, pt in self.selList do
pt.fWidth.value = pt.fTempWidth * offset
pt.fWidth.value = LM.Clamp(pt.fWidth.value, 0, maxWidth)
pt.fWidth:StoreValue()
end
end
mouseEvent.view:DrawMe()
end
function LM_ScalePoints:OnMouseUp(moho, mouseEvent)
local mesh = moho:Mesh()
if (mesh == nil) then
return
end
if (self.scalingDir < 0) then
return
end
if (self.numSel == 1) then
-- update the selected list
self.selList = MOHO.SelectedPointList(mesh)
end
-- clear out NULL width key values if there is more than one keyframe
for i, pt in self.selList do
if (pt.fWidth:CountKeys() > 1) then
for id = pt.fWidth:CountKeys() - 1, 0, -1 do
local when = pt.fWidth:GetKeyWhen(id)
if (pt.fWidth:GetValue(when) < 0) then
pt.fWidth:DeleteKey(when)
end
end
if (pt.fWidth:CountKeys() < 1) then
pt.fWidth:SetValue(0, -1)
end
end
end
self.selList = nil
moho.layer:UpdateCurFrame()
moho:NewKeyframe(CHANNEL_WIDTH)
moho:UpdateSelectedChannels()
moho:AddPointKeyframe(moho.frame)
moho:NewKeyframe(CHANNEL_POINT)
mouseEvent.view:DrawMe()
end
function LM_ScalePoints:OnKeyDown(moho, keyEvent)
LM_SelectPoints:OnKeyDown(moho, keyEvent)
end
function LM_ScalePoints:DrawMe(moho, view)
local mesh = moho:Mesh()
if (mesh == nil) then
return
end
local g = view:Graphics()
local min = LM.Vector2:new_local()
local max = LM.Vector2:new_local()
local markerR = 4
local matrix = LM.Matrix:new_local()
mesh:SelectedBounds(min, max)
moho.layer:GetFullTransform(moho.frame, matrix, moho.document)
g:Push()
g:ApplyMatrix(matrix)
g:SetColor(255, 0, 0)
g:SetSmoothing(true)
g:DrawLine(min.x, min.y, max.x, min.y)
g:DrawLine(min.x, max.y, max.x, max.y)
g:DrawLine(min.x, min.y, min.x, max.y)
g:DrawLine(max.x, min.y, max.x, max.y)
g:SetSmoothing(false)
g:DrawFatMarker(min.x, min.y, markerR)
g:DrawFatMarker(min.x, max.y, markerR)
g:DrawFatMarker(max.x, min.y, markerR)
g:DrawFatMarker(max.x, max.y, markerR)
g:DrawFatMarker((min.x + max.x) / 2, min.y, markerR)
g:DrawFatMarker((min.x + max.x) / 2, max.y, markerR)
g:DrawFatMarker(min.x, (min.y + max.y) / 2, markerR)
g:DrawFatMarker(max.x, (min.y + max.y) / 2, markerR)
g:Pop()
end
-- **************************************************
-- Tool options - create and respond to tool's UI
-- **************************************************
LM_ScalePoints.DUMMY = MOHO.MSG_BASE
LM_ScalePoints.MODIFY = MOHO.MSG_BASE + 1
LM_ScalePoints.RESET = MOHO.MSG_BASE + 2
LM_ScalePoints.SELECTITEM = MOHO.MSG_BASE + 3
function LM_ScalePoints:DoLayout(moho, layout)
self.menu = LM.GUI.Menu(MOHO.Localize(self.BASE_STR + 2, "Select Group"))
self.popup = LM.GUI.PopupMenu(128, false)
self.popup:SetMenu(self.menu)
layout:AddChild(self.popup)
layout:AddChild(LM.GUI.StaticText(MOHO.Localize(self.BASE_STR + 3, "Scale")))
layout:AddChild(LM.GUI.StaticText(MOHO.Localize(MOHO.STR_X, "X:")))
self.scaleX = LM.GUI.TextControl(0, "00.0000", 0, LM.GUI.FIELD_FLOAT)
layout:AddChild(self.scaleX)
layout:AddChild(LM.GUI.StaticText(MOHO.Localize(MOHO.STR_Y, "Y:")))
self.scaleY = LM.GUI.TextControl(0, "00.0000", 0, LM.GUI.FIELD_FLOAT)
layout:AddChild(self.scaleY)
layout:AddChild(LM.GUI.Button(MOHO.Localize(self.BASE_STR + 4, "Modify"), self.MODIFY))
layout:AddChild(LM.GUI.Button(MOHO.Localize(MOHO.STR_RESET, "Reset"), self.RESET))
end
function LM_ScalePoints:UpdateWidgets(moho)
local mesh = moho:Mesh()
if (mesh == nil) then
return
end
MOHO.BuildGroupMenu(self.menu, mesh, self.SELECTITEM, self.DUMMY)
self.scaleX:SetValue(1)
self.scaleY:SetValue(1)
end
function LM_ScalePoints:HandleMessage(moho, view, msg)
local mesh = moho:Mesh()
if (mesh == nil) then
return
end
if (msg == self.MODIFY) then
moho.document:PrepUndo(moho.layer)
moho.document:SetDirty()
local centerVec = mesh:SelectedCenter()
local scaleX = self.scaleX:FloatValue()
local scaleY = self.scaleY:FloatValue()
mesh:PrepMovePoints()
mesh:ScalePoints(scaleX, scaleY, centerVec)
moho:AddPointKeyframe(moho.frame)
moho:NewKeyframe(CHANNEL_POINT)
elseif (msg == self.RESET) then
if (moho.frame > 0) then
moho.document:PrepUndo(moho.layer)
moho.document:SetDirty()
for i = 0, mesh:CountPoints() - 1 do
local pt = mesh:Point(i)
if (pt.fSelected) then
pt:SetPos(pt.fAnimPos:GetValue(0), moho.frame)
end
end
end
moho:NewKeyframe(CHANNEL_POINT)
elseif (msg >= self.SELECTITEM) then
mesh:SelectNone()
local i = msg - self.SELECTITEM
local name = mesh:Group(i):Name()
mesh:SelectGroup(name)
moho:UpdateUI()
end
end