-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "SS_MultiLayerTransformPoints" -- ************************************************** -- Transform points on multiple layers -- based on: LM_TransformPoints 10.0 (Lost Marble) -- version: +01.04 MH12+ #530605 -- by: Sam Cogheil (SimplSam) -- ************************************************** SS_MultiLayerTransformPoints = {} -- SS_MultiLayerTransformPoints.BASE_STR = 2375 function SS_MultiLayerTransformPoints:Name() return "Multi-Layer Transform Points" end function SS_MultiLayerTransformPoints:Version() return "10+01.04 #5306" end function SS_MultiLayerTransformPoints:Description() return "Move/Scale/Rotate selected points on multiple layers (hold <shift> to constrain, <alt> to scale to center, <shift> while scaling to squash, <ctrl/cmd> to select points)" end function SS_MultiLayerTransformPoints:Creator() return "Lost Marble LLC + Sam Cogheil (SimplSam)" end function SS_MultiLayerTransformPoints:UILabel() return ("Multi-Layer Transform Points") -- return (MOHO.Localize("/Scripts/Tool/TransformPoints/TransformPoints=Multi-Layer Transform Points")) end function SS_MultiLayerTransformPoints:LoadPrefs(prefs) self.autoWeld = prefs:GetBool("SS_MultiLayerTransformPoints.autoWeld", false) self.autoFill = prefs:GetBool("SS_MultiLayerTransformPoints.autoFill", false) self.autoStroke = prefs:GetBool("SS_MultiLayerTransformPoints.autoStroke", false) self.showHandles = prefs:GetBool("SS_MultiLayerTransformPoints.showHandles", false) self.fixedHandles = prefs:GetBool("SS_MultiLayerTransformPoints.fixedHandles", false) end function SS_MultiLayerTransformPoints:SavePrefs(prefs) prefs:SetBool("SS_MultiLayerTransformPoints.autoWeld", self.autoWeld) prefs:SetBool("SS_MultiLayerTransformPoints.autoFill", self.autoFill) prefs:SetBool("SS_MultiLayerTransformPoints.autoStroke", self.autoStroke) prefs:SetBool("SS_MultiLayerTransformPoints.showHandles", self.showHandles) prefs:SetBool("SS_MultiLayerTransformPoints.fixedHandles", self.fixedHandles) end function SS_MultiLayerTransformPoints:ResetPrefs() SS_MultiLayerTransformPoints.autoWeld = false SS_MultiLayerTransformPoints.autoWeldRadius = 12 SS_MultiLayerTransformPoints.autoFill = false SS_MultiLayerTransformPoints.autoStroke = false SS_MultiLayerTransformPoints.showHandles = false SS_MultiLayerTransformPoints.fixedHandles = true end function SS_MultiLayerTransformPoints:ColorizeIcon() return true end function SS_MultiLayerTransformPoints:NonDragMouseMove() return true -- Call MouseMoved() even if the mouse button is not down end function SS_MultiLayerTransformPoints:HideConstructionCurves(moho) return false -- true end -- ************************************************** -- Recurring values -- ************************************************** SS_MultiLayerTransformPoints.dragging = false SS_MultiLayerTransformPoints.keyMovement = false SS_MultiLayerTransformPoints.mode = 0 -- 0:translate, 1:rotate, 2:top left scale, 3:top right scale, 4: bottom left scale, 5: bottom right scale, 6:left scale, 7:right scale, 8:top scale, 9:bottom scale, 10:bezier handle, 11:pivot offset, 100:select points SS_MultiLayerTransformPoints.MODE_TRANS = 0 SS_MultiLayerTransformPoints.MODE_ROTATE = 1 SS_MultiLayerTransformPoints.MODE_SCALE_ = 2 SS_MultiLayerTransformPoints.MODE_SCALE_TOPLFT = 2 SS_MultiLayerTransformPoints.MODE_SCALE_TOPRGT = 3 SS_MultiLayerTransformPoints.MODE_SCALE_BOTLFT = 4 SS_MultiLayerTransformPoints.MODE_SCALE_BOTRGT = 5 SS_MultiLayerTransformPoints.MODE_SCALE_LEFT = 6 SS_MultiLayerTransformPoints.MODE_SCALE_RIGHT = 7 SS_MultiLayerTransformPoints.MODE_SCALE_TOP = 8 SS_MultiLayerTransformPoints.MODE_SCALE_BOT = 9 SS_MultiLayerTransformPoints.MODE_SCALE_MAX_ = 9 SS_MultiLayerTransformPoints.MODE_BEZIER = 10 SS_MultiLayerTransformPoints.MODE_PIVOT = 11 SS_MultiLayerTransformPoints.MODE_SELECT = 100 SS_MultiLayerTransformPoints.numSel = 0 SS_MultiLayerTransformPoints.selID = -1 SS_MultiLayerTransformPoints.fillingShape = false SS_MultiLayerTransformPoints.NumNotSet = -10000000 SS_MultiLayerTransformPoints.endWeldVec = LM.Vector2:new_local() SS_MultiLayerTransformPoints.endWeldVec:Set(SS_MultiLayerTransformPoints.NumNotSet, SS_MultiLayerTransformPoints.NumNotSet) SS_MultiLayerTransformPoints.endWeldToPoint = true SS_MultiLayerTransformPoints.startAngle = 0 SS_MultiLayerTransformPoints.lastVec = LM.Vector2:new_local() SS_MultiLayerTransformPoints.lastVecPt = LM.Point:new_local() SS_MultiLayerTransformPoints.pivotCenterVec = LM.Vector2:new_local() SS_MultiLayerTransformPoints.pivotCenterVec:Set(SS_MultiLayerTransformPoints.NumNotSet, SS_MultiLayerTransformPoints.NumNotSet) SS_MultiLayerTransformPoints.lastSelectedCount = 0 SS_MultiLayerTransformPoints.pivotOffset = LM.Vector2:new_local() SS_MultiLayerTransformPoints.markerR = 8 SS_MultiLayerTransformPoints.selMesh = nil SS_MultiLayerTransformPoints.selLayer = nil SS_MultiLayerTransformPoints.selCenter = LM.Vector2:new_local() SS_MultiLayerTransformPoints.selCenter3z = LM.Vector3:new_local() SS_MultiLayerTransformPoints.selectedMin = LM.Vector2:new_local() SS_MultiLayerTransformPoints.selectedMax = LM.Vector2:new_local() SS_MultiLayerTransformPoints.centerVecPt = LM.Point:new_local() SS_MultiLayerTransformPoints.offsetCenterPt = LM.Point:new_local() SS_MultiLayerTransformPoints.selCenterIsDirty = true SS_MultiLayerTransformPoints.mmeshPickWidth = 6 SS_MultiLayerTransformPoints.allowShapePicking = true SS_MultiLayerTransformPoints.lastFrame = SS_MultiLayerTransformPoints.NumNotSet SS_MultiLayerTransformPoints.multiMeshes = {} SS_MultiLayerTransformPoints.multiSelectedPointsCount = -1 SS_MultiLayerTransformPoints.AltKeyCode1 = 92 -- backslash SS_MultiLayerTransformPoints.AltKeyCode2 = 96 -- backtick math.atan2 = math.atan2 or math.atan -- ************************************************** -- The guts of this script -- ************************************************** function SS_MultiLayerTransformPoints:IsEnabled(moho) self.selCenterIsDirty = true return true end function SS_MultiLayerTransformPoints:IsRelevant(moho) local mesh = moho:DrawingMesh() if (mesh or moho.layer:IsGroupType()) then self.numSel = self:MultimeshCountSelectedPoints(moho, true) self.selCenterIsDirty = true return true else return false end end function SS_MultiLayerTransformPoints:MultimeshCountPoints(moho) local _count = 0 for _, mmesh in pairs(self.multiMeshes) do _count = _count + mmesh.mesh:CountPoints() end return _count end function SS_MultiLayerTransformPoints:MultimeshCountSelectedPoints(moho, doRecalc) local function MeshCountSelectedPoints(_mesh) local count = 0 for i = 0, _mesh:CountPoints() - 1 do count = count + (_mesh:Point(i).fSelected and 1 or 0) end return count end if (doRecalc or (self.multiSelectedPointsCount == -1)) then self.multiMeshes = {} self.multiLayersCount = 0 self.multiSelectedPointsCount = 0 self.multiPointsCount = 0 local function ProcessLayer(_layer) if (_layer:IsGroupType()) then local groupLayer = moho:LayerAsGroup(_layer) for j = 0, groupLayer:CountLayers() - 1 do ProcessLayer(groupLayer:Layer(j)) end else if (_layer:LayerType() == MOHO.LT_VECTOR) and (not self.multiMeshes[moho.document:LayerAbsoluteID(_layer) + 1]) then local mmesh = {} mmesh.layer = _layer mmesh.mesh = moho:LayerAsVector(mmesh.layer):Mesh() mmesh.pointsCount = mmesh.mesh:CountPoints() if (mmesh.pointsCount > 0) then self.multiLayersCount = self.multiLayersCount + 1 mmesh.selectedPointsCount = MeshCountSelectedPoints(mmesh.mesh) self.multiMeshes[moho.document:LayerAbsoluteID(mmesh.layer) + 1] = mmesh self.multiSelectedPointsCount = self.multiSelectedPointsCount + mmesh.selectedPointsCount end self.multiPointsCount = self.multiPointsCount + mmesh.pointsCount end end end for i = 0, moho.document:CountSelectedLayers() - 1 do ProcessLayer(moho.document:GetSelectedLayer(i)) end end return self.multiSelectedPointsCount end -- Find nearesrt point - in 'Group children + Selected layers' function SS_MultiLayerTransformPoints:MultimeshPickClosestPoint(moho, pt, pickWidth) -- pt not vec local lastMag = pickWidth or 10000000 lastMag = lastMag + 1 local lastPointID = -1 local lastLayer, lastMesh local m = LM.Matrix:new_local() for _, mmesh in pairs(self.multiMeshes) do mmesh.layer:GetFullTransform(moho.frame, m, moho.document) local v = moho.view:Point2Vec(pt, m) local pointID = mmesh.mesh:ClosestPoint(v) if (pointID ~= -1) then local point = mmesh.mesh:Point(pointID) local ptPos = LM.Point:new_local() local vcPos = LM.Vector2:new_local() vcPos:Set(point.fPos) m:Transform(vcPos) moho.view:Graphics():WorldToScreen(vcPos, ptPos) local mag = math.abs(ptPos.x - pt.x) + math.abs(ptPos.y - pt.y) if (mag < lastMag) then lastPointID = pointID lastMesh = mmesh.mesh lastLayer = mmesh.layer lastMag = mag end end end return lastLayer, lastMesh, lastPointID, lastMag end function SS_MultiLayerTransformPoints:MultimeshMovePoints(moho, offset) if (self.multiSelectedPointsCount < 1) then return end local m = LM.Matrix:new_local() local vec = LM.Vector2:new_local() local vec3zFrom = LM.Vector3:new_local() local vec3zTo = LM.Vector3:new_local() for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then if (self:UseFixedHandles(moho)) then mmesh.mesh:PrepFixedHandles() end mmesh.layer:GetFullTransform(moho.frame, m, moho.document) m:Invert() vec3zFrom:Set(self.centerVec3z) vec3zTo:Set(self.centerVec3z.x + offset.x, self.centerVec3z.y + offset.y, self.centerVec3z.z) if (moho.gridOn) and (self.multiSelectedPointsCount == 1) then local snapVec = LM.Vector2:new_local() snapVec:Set(vec3zTo.x, vec3zTo.y) moho:SnapToGrid(snapVec) vec3zTo.x, vec3zTo.y = snapVec.x, snapVec.y end m:Transform(vec3zFrom) m:Transform(vec3zTo) vec:Set(vec3zTo.x - vec3zFrom.x, vec3zTo.y - vec3zFrom.y) mmesh.mesh:TranslatePoints(vec) moho:AddPointKeyframe(moho.drawingFrame, mmesh.layer, true) -- MOHO.MohoGlobals.EditMultipleKeys) if (self:UseFixedHandles(moho)) then mmesh.mesh:PreserveHandlePositions() end end end end function SS_MultiLayerTransformPoints:MultimeshSelectedMeshBounds(moho, frame, view) local bbox = LM.BBox:new_local() local vec = LM.Vector2:new_local() local m = LM.Matrix:new_local() -- pre-Transform for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.layer:GetFullTransform(frame, m, moho.document) for i = 0, mmesh.mesh:CountPoints() - 1 do if (mmesh.mesh:Point(i).fSelected) then vec:Set(mmesh.mesh:Point(i).fPos) m:Transform(vec) bbox:AccumulatePoint(vec) end end end end -- make sure the bounding box is not too thin in one direction local xLen = bbox.fMax.x - bbox.fMin.x local yLen = bbox.fMax.y - bbox.fMin.y local center if (xLen < yLen / 10.0) then center = (bbox.fMin.x + bbox.fMax.x) / 2.0 bbox.fMin.x = center - yLen / 10.0 bbox.fMax.x = center + yLen / 10.0 elseif (yLen < xLen / 10.0) then center = (bbox.fMin.y + bbox.fMax.y) / 2.0 bbox.fMin.y = center - xLen / 10.0 bbox.fMax.y = center + xLen / 10.0 end -- make sure the bounding box is not too small local minLength = 150 local v = LM.Vector2:new_local() local pt1 = LM.Point:new_local() local pt2 = LM.Point:new_local() v:Set(bbox.fMin.x, bbox.fMin.y) view:Graphics():WorldToScreen(v, pt1) v:Set(bbox.fMax.x, bbox.fMax.y) view:Graphics():WorldToScreen(v, pt2) pt1 = pt2 - pt1 local length = math.sqrt(pt1.x * pt1.x + pt1.y * pt1.y) if (length < minLength) then center = (bbox.fMin + bbox.fMax) / 2.0 v = bbox.fMax - center bbox.fMax = center + v * (minLength / length) / 2.0 v = bbox.fMin - center bbox.fMin = center + v * (minLength / length) / 2.0 end return bbox end function SS_MultiLayerTransformPoints:MultimeshTestMousePoint(moho, mouseEvent) -- Returns what mode the tool would be in if the user clicked at the current mouse location self.numSel = self:MultimeshCountSelectedPoints(moho) -- moho:CountSelectedPoints() if (self.numSel < 2) then return self.MODE_TRANS end local bbox = self:MultimeshSelectedMeshBounds(moho, moho.frame, mouseEvent.view) local v = LM.Vector2:new_local() local pt = LM.Point:new_local() -- #SC test for Pivot first (priority) -- test for pivot point if (self.dragging) then v:Set(self.centerVec) else v = self:MultimeshSelectedCenter(moho) + self.pivotOffset end mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_PIVOT end -- test for uniform scaling v:Set(bbox.fMin.x, bbox.fMin.y) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_BOTLFT end v:Set(bbox.fMin.x, bbox.fMax.y) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_TOPLFT end v:Set(bbox.fMax.x, bbox.fMax.y) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_TOPRGT end v:Set(bbox.fMax.x, bbox.fMin.y) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_BOTRGT end -- test for X scaling v:Set(bbox.fMin.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_LEFT end v:Set(bbox.fMax.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_RIGHT end -- test for Y scaling v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_BOT end v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then return self.MODE_SCALE_TOP end -- test for translation outside the bounding box mouseEvent.view:Graphics():ScreenToWorld(mouseEvent.pt, v) local rotWidth = bbox.fMax.x - bbox.fMin.x if (bbox.fMax.y - bbox.fMin.y > rotWidth) then rotWidth = bbox.fMax.y - bbox.fMin.y end rotWidth = rotWidth * 0.1 if (v.x < bbox.fMin.x - rotWidth or v.x > bbox.fMax.x + rotWidth or v.y < bbox.fMin.y - rotWidth or v.y > bbox.fMax.y + rotWidth) then -- #SC return self.MODE_TRANS end -- test for rotation if (v.x < bbox.fMin.x or v.x > bbox.fMax.x or v.y < bbox.fMin.y or v.y > bbox.fMax.y) then -- #SC return self.MODE_ROTATE end return self.MODE_TRANS -- translation inside the bounding box end function SS_MultiLayerTransformPoints:MultimeshSelectNone() for _, mmesh in pairs(self.multiMeshes) do mmesh.mesh:SelectNone() end self.multiSelectedPointsCount = 0 end function SS_MultiLayerTransformPoints:MultimeshSelectAll(moho) for _, mmesh in pairs(self.multiMeshes) do mmesh.mesh:SelectAll() end self:MultimeshSelectedCenter(moho, true) end function SS_MultiLayerTransformPoints:MultimeshSelectConnected(moho) for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:SelectConnected() end end self:MultimeshSelectedCenter(moho, true) end function SS_MultiLayerTransformPoints:MultimeshSelectedBounds(moho) local bbox = LM.BBox:new_local() local m = LM.Matrix:new_local() local v3 = LM.Vector3:new_local() -- pre-Transform + also reCount points/selected self.multiPointsCount = 0 self.multiSelectedPointsCount = 0 for _, mmesh in pairs(self.multiMeshes) do mmesh.selectedPointsCount = 0 mmesh.layer:GetFullTransform(moho.drawingFrame, m, moho.document) mmesh.pointsCount = mmesh.mesh:CountPoints() for i = 0, mmesh.pointsCount - 1 do if (mmesh.mesh:Point(i).fSelected) then v3:Set(mmesh.mesh:Point(i).fPos.x, mmesh.mesh:Point(i).fPos.y, 0) m:Transform(v3) bbox:AccumulatePoint(v3) mmesh.selectedPointsCount = mmesh.selectedPointsCount + 1 end end self.multiPointsCount = self.multiPointsCount + mmesh.pointsCount self.multiSelectedPointsCount = self.multiSelectedPointsCount + mmesh.selectedPointsCount end return bbox -- 3D end function SS_MultiLayerTransformPoints:MultimeshSelectedCenter(moho, doRecalc) -- #SC called in Draw if (doRecalc or self.selCenterIsDirty or (moho.drawingFrame ~= self.lastFrame)) then self.selBBox = self:MultimeshSelectedBounds(moho) self.selCenter:Set(self.selBBox:Center2D()) self.selCenter3z:Set(self.selBBox:Center()) self.selCenterIsDirty = false self.lastFrame = moho.drawingFrame end return self.selCenter, self.selCenter3z, self.selBBox end function SS_MultiLayerTransformPoints:MultimeshSelectOnMouseDown(moho, mouseEvent) self.selCenterIsDirty = true LM_SelectPoints.isMouseDragging = true local lassoMode = false LM_SelectPoints.ctrlKeySelection = false if (LM_SelectPoints.lassoMode) then if (not (mouseEvent.ctrlKey)) then lassoMode = true else LM_SelectPoints.ctrlKeySelection = true end else if (mouseEvent.ctrlKey) then lassoMode = true LM_SelectPoints.ctrlKeySelection = true end end LM_SelectPoints.selMode = LM_SelectPoints.SELMODE_GROUP_PTS if (not mouseEvent.shiftKey and not mouseEvent.altKey) then self:MultimeshSelectNone() -- #SC Only 1 lined changed end if (LM_SelectPoints.selMode == LM_SelectPoints.SELMODE_GROUP_PTS) then if (lassoMode) then LM_SelectPoints.lassoList = {{mouseEvent.startPt.x, mouseEvent.startPt.y}} LM_SelectPoints.previousX = mouseEvent.startPt.x LM_SelectPoints.previousY = mouseEvent.startPt.y else LM_SelectPoints.selRect.left = mouseEvent.startPt.x LM_SelectPoints.selRect.top = mouseEvent.startPt.y LM_SelectPoints.selRect.right = mouseEvent.pt.x LM_SelectPoints.selRect.bottom = mouseEvent.pt.y mouseEvent.view:Graphics():SelectionRect(LM_SelectPoints.selRect) end end mouseEvent.view:DrawMe() end function SS_MultiLayerTransformPoints:OnMouseDown(moho, mouseEvent) self.dragging = true self.endWeldVec:Set(self.NumNotSet, self.NumNotSet) self.pivotCenterVec:Set(self.NumNotSet, self.NumNotSet) self.centerVec = self:MultimeshSelectedCenter(moho) self.centerVec = self.centerVec + self.pivotOffset self.startPivotOffset = LM.Vector2:new_local() self.startPivotOffset:Set(self.pivotOffset) self.startPivotOffsetPt = LM.Point:new_local() -- #SC mouseEvent.view:Graphics():WorldToScreen(self.startPivotOffset, self.startPivotOffsetPt) mouseEvent.view:Graphics():WorldToScreen(self.centerVec, self.centerVecPt) self.mode = self:MultimeshTestMousePoint(moho, mouseEvent) if (mouseEvent.ctrlKey) then self.mode = self.MODE_SELECT mouseEvent.ctrlKey = false self:MultimeshSelectOnMouseDown(moho, mouseEvent) -- LM_SelectPoints:OnMouseDown(moho, mouseEvent) return end local bbox = self:MultimeshSelectedBounds(moho) self.selectedMin, self.selectedMax = bbox.fMin, bbox.fMax self.selectedMin.y, self.selectedMax.y = self.selectedMax.y, self.selectedMin.y -- make min Y at Top moho.document:SetDirty() self.numSel = self:MultimeshCountSelectedPoints(moho, true) -- self.numSel = moho:CountSelectedPoints(true) if (self.selID == -1) then -- if this isn't true, then a point has already been selected (maybe by the add point tool) -- if (self.mode == self.MODE_TRANS and self.numSel < 2 and self.showHandles) then -- #SC -- LM_Curvature:TestForClosestHandle(moho, mouseEvent) -- if (LM_Curvature.selID >= 0 and LM_Curvature.handleSide ~= 0) then -- a bezier handle was selected -- self.mode = self.MODE_BEZIER -- local point = mesh:Point(LM_Curvature.selID) -- if (point:IsEndpoint()) then -- -- If working with a curve endpoint, and its handles have not been extended, don't do it with this tool. -- -- It's preferable to just move the endpoint. -- -- If the user wants to move the handle, they must use the curvature tool. -- local curve = nil -- local ptPos = -1 -- curve, ptPos = point:Curve(0, ptPos) -- local weight = curve:GetWeight(ptPos, moho.drawingFrame, LM_Curvature.handleSide == -1) -- local offset = curve:GetOffset(ptPos, moho.drawingFrame, LM_Curvature.handleSide == -1) -- local wDiff = weight - 1.0 -- local oDiff = offset - 0.0 -- if (math.abs(wDiff) < 0.0001 and math.abs(oDiff) < 0.0001 and curve:CountPoints() > 2) then -- self.mode = self.MODE_TRANS -- end -- end -- end -- self.selID = -1 -- self.handleSide = 0 -- end -- if (self.mode ~= self.MODE_PIVOT) then moho.document:PrepUndo() -- end end if (self.mode == self.MODE_TRANS) then -- translate if (self.selID == -1) then mouseEvent.shiftKey = mouseEvent.altKey mouseEvent.ctrlKey = mouseEvent.altKey self.numSel = self:MultimeshCountSelectedPoints(moho) -- self.numSel = moho:CountSelectedPoints(true) if (self.numSel < 2) then -- move just a single point local pickWidth if (self.numSel < 1) then -- else nil pickWidth = self.mmeshPickWidth * 10 end self.selLayer, self.selMesh, self.selID = self:MultimeshPickClosestPoint(moho, mouseEvent.startPt, pickWidth) if (self.selMesh and self.selID >= 0) then self.numSel = 1 self:MultimeshSelectNone() self.selMesh:Point(self.selID).fSelected = true self.numSel = self:MultimeshCountSelectedPoints(moho, true) else self.mode = self.MODE_SELECT self:MultimeshSelectOnMouseDown(moho, mouseEvent) return end else self.selLayer, self.selMesh, self.selID = self:MultimeshPickClosestPoint(moho, mouseEvent.startPt) end end elseif (self.mode == self.MODE_ROTATE) then -- rotate mouseEvent.shiftKey = mouseEvent.altKey mouseEvent.ctrlKey = mouseEvent.altKey self.numSel = self:MultimeshCountSelectedPoints(moho, true) self.startAngle = 0 self.lastVec:Set(mouseEvent.drawingVec) self.lastVecPt:Set(mouseEvent.pt) elseif (self.mode == self.MODE_BEZIER) then -- bezier handle LM_Curvature:OnMouseDown(moho, mouseEvent) return elseif (self.mode == self.MODE_PIVOT) then -- pivot point self.numSel = self:MultimeshCountSelectedPoints(moho, true) self.lastVec:Set(mouseEvent.drawingVec) else -- scale self.lastScaleX = 1.0 self.lastScaleY = 1.0 if (self.numSel < 2) then mouseEvent.shiftKey = mouseEvent.altKey mouseEvent.ctrlKey = mouseEvent.altKey self.numSel = self:MultimeshCountSelectedPoints(moho, true) end if (self.numSel < 2) then mouseEvent.view:DrawMe() return end local selectedMaxPt = LM.Point:new_local() local selectedMinPt = LM.Point:new_local() local center = LM.Vector2:new_local() if (mouseEvent.altKey or self.isPivotSet) then center:Set(self.centerVec3z.x + self.pivotOffset.x, self.centerVec3z.y + self.pivotOffset.y) mouseEvent.view:Graphics():WorldToScreen(center, self.offsetCenterPt) mouseEvent.altKey = true else mouseEvent.view:Graphics():WorldToScreen(self.selectedMin, selectedMinPt) mouseEvent.view:Graphics():WorldToScreen(self.selectedMax, selectedMaxPt) if (self.mode == self.MODE_SCALE_LEFT) then -- LEFT self.offsetCenterPt:Set(selectedMaxPt.x, (selectedMinPt.y + selectedMaxPt.y) / 2.0) elseif (self.mode == self.MODE_SCALE_RIGHT) then -- RIGHT self.offsetCenterPt:Set(selectedMinPt.x, (selectedMinPt.y + selectedMaxPt.y) / 2.0) elseif (self.mode == self.MODE_SCALE_TOP) then -- TOP self.offsetCenterPt:Set((selectedMinPt.x + selectedMaxPt.x) / 2.0, selectedMaxPt.y) elseif (self.mode == self.MODE_SCALE_BOT) then -- BOTTOM self.offsetCenterPt:Set((selectedMinPt.x + selectedMaxPt.x) / 2.0, selectedMinPt.y) elseif (self.mode == self.MODE_SCALE_BOTLFT) then -- BL self.offsetCenterPt:Set(selectedMaxPt.x, selectedMinPt.y) elseif (self.mode == self.MODE_SCALE_TOPLFT) then -- TL self.offsetCenterPt:Set(selectedMaxPt.x, selectedMaxPt.y) elseif (self.mode == self.MODE_SCALE_TOPRGT) then -- TR self.offsetCenterPt:Set(selectedMinPt.x, selectedMaxPt.y) elseif (self.mode == self.MODE_SCALE_BOTRGT) then -- BR self.offsetCenterPt:Set(selectedMinPt.x, selectedMinPt.y) end end end for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:PrepMovePoints() end end mouseEvent.view:DrawMe() moho:UpdateUI() end function SS_MultiLayerTransformPoints:MultimeshSelectOnMouseMoved(moho, mouseEvent) local lassoMode = false if (LM_SelectPoints.lassoMode) then if (not (LM_SelectPoints.ctrlKeySelection)) then lassoMode = true end else if (LM_SelectPoints.ctrlKeySelection) then lassoMode = true end end if (LM_SelectPoints.selMode == LM_SelectPoints.SELMODE_GROUP_PTS) then if (lassoMode) then local g = mouseEvent.view:Graphics() g:SetSmoothing(true) g:Push() local m = g:CurrentTransform() m:Invert() g:ApplyMatrix(m) g:SetColor(MOHO.MohoGlobals.SelCol) g:MoveTo(LM_SelectPoints.previousX, LM_SelectPoints.previousY) g:LineTo(mouseEvent.pt.x, mouseEvent.pt.y) g:Pop() g:SetSmoothing(false) mouseEvent.view:RefreshView() table.insert(LM_SelectPoints.lassoList, {mouseEvent.pt.x, mouseEvent.pt.y}) LM_SelectPoints.previousX = mouseEvent.pt.x LM_SelectPoints.previousY = mouseEvent.pt.y else mouseEvent.view:Graphics():SelectionRect(LM_SelectPoints.selRect) LM_SelectPoints.selRect.right = mouseEvent.pt.x LM_SelectPoints.selRect.bottom = mouseEvent.pt.y mouseEvent.view:Graphics():SelectionRect(LM_SelectPoints.selRect) mouseEvent.view:RefreshView() end mouseEvent.view:DrawMe() end end function SS_MultiLayerTransformPoints:OnMouseMoved(moho, mouseEvent) if (not self.dragging) then self.centerVec, self.centerVec3z = self:MultimeshSelectedCenter(moho) local mode = self:MultimeshTestMousePoint(moho, mouseEvent) if (mode == self.MODE_TRANS) then if (self.numSel == 0) then local _, _, selID = self:MultimeshPickClosestPoint(moho, mouseEvent.pt, self.mmeshPickWidth * 10) if (selID >= 0) then mouseEvent.view:SetCursor(MOHO.moveCursor) else mouseEvent.view:SetCursor(MOHO.crosshairCursor) return end else mouseEvent.view:SetCursor(MOHO.moveCursor) end elseif (mode == self.MODE_ROTATE) then mouseEvent.view:SetCursor(MOHO.rotateCursor) elseif (mode == self.MODE_PIVOT) then mouseEvent.view:SetCursor(MOHO.crosshairCursor) else mouseEvent.view:SetCursor(MOHO.scaleCursor) end mouseEvent.view:DrawMe() return end if (self.mode == self.MODE_SELECT) then mouseEvent.ctrlKey = false self:MultimeshSelectOnMouseMoved(moho, mouseEvent) -- LM_SelectPoints:OnMouseMoved(moho, mouseEvent) elseif (self.mode == self.MODE_TRANS) then self:OnMouseMoved_T(moho, mouseEvent) elseif (self.mode == self.MODE_ROTATE) then self:OnMouseMoved_R(moho, mouseEvent) elseif (self.mode == self.MODE_BEZIER) then LM_Curvature:OnMouseMoved(moho, mouseEvent) return elseif (self.mode == self.MODE_PIVOT) then self:OnMouseMoved_P(moho, mouseEvent) else -- scale self:OnMouseMoved_S(moho, mouseEvent) end end function SS_MultiLayerTransformPoints:OnMouseMoved_T(moho, mouseEvent) if (mouseEvent.ctrlKey) then -- hold down the control key to just select a single point and not move it return end self:MultimeshCountSelectedPoints(moho) -- ? local curVec3z = LM.Vector3:new_local() local startVec3z = LM.Vector3:new_local() local m = LM.Matrix:new_local() startVec3z:Set(mouseEvent.drawingStartVec.x, mouseEvent.drawingStartVec.y, 0) curVec3z:Set(mouseEvent.drawingVec.x, mouseEvent.drawingVec.y, 0) moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) m:Transform(startVec3z) m:Transform(curVec3z) if (mouseEvent.shiftKey) then if (math.abs(curVec3z.x - startVec3z.x) > math.abs(curVec3z.y - startVec3z.y)) then curVec3z.y = startVec3z.y else curVec3z.x = startVec3z.x end end if (moho.gridOn) and (self.multiSelectedPointsCount > 1) then local snapVec = LM.Vector2:new_local() snapVec:Set(curVec3z.x, curVec3z.y) moho:SnapToGrid(snapVec) curVec3z.x, curVec3z.y = snapVec.x, snapVec.y end local mouseDist = math.abs(mouseEvent.pt.x - mouseEvent.startPt.x) + math.abs(mouseEvent.pt.y - mouseEvent.startPt.y) if (mouseDist >= 4) then self:MultimeshMovePoints(moho, curVec3z - startVec3z) end mouseEvent.view:DrawMe() end function SS_MultiLayerTransformPoints:OnMouseMoved_S(moho, mouseEvent) if (self.numSel < 2) then return end local center = LM.Vector2:new_local() local scaling = LM.Vector2:new_local() local p1 = mouseEvent.startPt - self.offsetCenterPt -- self.centerVecPt local p2 = mouseEvent.pt - self.offsetCenterPt -- self.centerVecPt scaling.x = p2.x / p1.x scaling.y = p2.y / p1.y if (self.mode == 6 or self.mode == 7) then -- horizontal scaling scaling.y = 1 if (mouseEvent.shiftKey) then scaling.y = 1 / scaling.x end elseif (self.mode == 8 or self.mode == 9) then -- vertical scaling scaling.x = 1 if (mouseEvent.shiftKey) then scaling.x = 1 / scaling.y end else if (not mouseEvent.shiftKey) then scaling.x = (scaling.x + scaling.y) / 2 scaling.y = scaling.x end end local flip = false if (scaling.x * self.lastScaleX < -0.0001) and (scaling.y * self.lastScaleY > 0.0001) then flip = true elseif (scaling.y * self.lastScaleY < -0.0001) and (scaling.x * self.lastScaleX > 0.0001) then flip = true end local mInv = LM.Matrix:new_local() local vec = LM.Vector2:new_local() local vec3 = LM.Vector3:new_local() local lVec = LM.Vector2:new_local() local scaleVec = LM.Vector2:new_local() local angle moho.view:Graphics():ScreenToWorld(self.offsetCenterPt, center) self.pivotCenterVec:Set(center) for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then scaleVec:Set(scaling) mmesh.layer:GetFullTransform(moho.frame, mInv, moho.document) mInv:Invert() lVec:Set(1, 0) mInv:Transform(lVec) angle = math.deg(math.atan2(lVec.y, lVec.x)) if ((angle > 45) and (angle < 135)) or ((angle < -45) and ((angle > -135))) then scaleVec.x, scaleVec.y = scaleVec.y, scaleVec.x end vec3:Set(center.x, center.y, self.centerVec3z.z) mInv:Transform(vec3) vec:Set(vec3.x, vec3.y) mmesh.mesh:ScalePoints(scaleVec.x, scaleVec.y, vec, flip) moho:AddPointKeyframe(moho.frame, mmesh.layer, MOHO.MohoGlobals.EditMultipleKeys) if (self:UseFixedHandles(moho)) then mmesh.mesh:PreserveHandlePositions() end end end if (mouseEvent.altKey) then self.pivotOffset = self.pivotCenterVec - self:MultimeshSelectedCenter(moho) -- , true) else local v = self.centerVec - center v.x = v.x * scaling.x v.y = v.y * scaling.y v = v + center self.pivotOffset = v - self:MultimeshSelectedCenter(moho, true) end if (flip) then self.lastScaleX = scaling.x self.lastScaleY = scaling.y end mouseEvent.view:DrawMe() end function SS_MultiLayerTransformPoints:OnMouseMoved_R(moho, mouseEvent) if (self.numSel < 2) then return end local v1, v2 = LM.Vector2:new_local(), LM.Vector2:new_local() local angle = self.startAngle local p1 = self.lastVecPt - self.centerVecPt local p2 = mouseEvent.pt - self.centerVecPt v1:Set(p1.x, -p1.y) v2:Set(p2.x, -p2.y) v2:Rotate(-math.atan2(v1.y, v1.x)) angle = angle + math.atan2(v2.y, v2.x) self.startAngle = angle if (mouseEvent.shiftKey) then angle = angle / (math.pi / 8) angle = (math.pi / 8) * LM.Round(angle) end local mInv = LM.Matrix:new_local() local vec3 = LM.Vector3:new_local() local vec = LM.Vector2:new_local() self.pivotCenterVec:Set(self.selCenter3z.x + self.pivotOffset.x, self.selCenter3z.y + self.pivotOffset.y) for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then local _angle = angle if (mmesh.layer.fFlipH.value ~= mmesh.layer.fFlipV.value) then _angle = -_angle end mmesh.layer:GetFullTransform(moho.frame, mInv, moho.document) mInv:Invert() vec3:Set(self.pivotCenterVec.x, self.pivotCenterVec.y, self.selCenter3z.z) mInv:Transform(vec3) vec:Set(vec3.x, vec3.y) mmesh.mesh:RotatePoints(_angle, vec) moho:AddPointKeyframe(moho.frame, mmesh.layer, true) if (self:UseFixedHandles(moho)) then mmesh.mesh:PreserveHandlePositions() end end end self.lastVecPt:Set(mouseEvent.pt) -- self.lastVec:Set(mouseEvent.drawingVec) mouseEvent.view:DrawMe() end function SS_MultiLayerTransformPoints:OnMouseMoved_P(moho, mouseEvent) local curPt = mouseEvent.pt - mouseEvent.startPt if (false and mouseEvent.ctrlKey) then -- #SC Set to 0,0 on Canvas -- local v = self:MultimeshSelectedCenter(moho) -- self.pivotOffset:Set(-v.x, -v.y) else if (mouseEvent.shiftKey) then if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then curPt.y = 0 else curPt.x = 0 end end self.pivotOffsetPt = self.startPivotOffsetPt + curPt mouseEvent.view:Graphics():ScreenToWorld(self.pivotOffsetPt, self.pivotOffset) self.centerVec = self:MultimeshSelectedCenter(moho) + self.pivotOffset if (moho.gridOn) then moho:SnapToGrid(self.centerVec) self.pivotOffset = self.centerVec - self:MultimeshSelectedCenter(moho) end end mouseEvent.view:DrawMe() end function SS_MultiLayerTransformPoints:MultimeshSelectSingleClickSelect(moho, mouseEvent, tryToPreserveSelection, allowEmptySelection) -- if tryToPreserveSelection is true, then don't change the selection if some points will remain selected self:MultimeshCountSelectedPoints(moho, true) if (self.multiPointsCount < 1) then return end if (tryToPreserveSelection and self.multiSelectedPointsCount < 2) then -- self:MultimeshCountSelectedPoints(moho) -- moho:CountSelectedPoints() self:MultimeshSelectNone() end if (not tryToPreserveSelection and not mouseEvent.shiftKey and not mouseEvent.altKey) then self:MultimeshSelectNone() end local layer, mesh, id = self:MultimeshPickClosestPoint(moho, mouseEvent.pt, self.mmeshPickWidth * 2) local p = LM.Point:new_local() local c = LM.Point:new_local() -- cursor local m = LM.Matrix:new_local() local v = LM.Vector2:new_local() c:Set(mouseEvent.pt) if (id >= 0) then -- pick a point moho.layer:GetFullTransform(moho.drawingFrame, m, moho.document) v:Set(mesh:Point(id).fPos) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, p) self.selMode = self.SELMODE_PT if (tryToPreserveSelection) then if (not mesh:Point(id).fSelected) then self:MultimeshSelectNone() end end if (mouseEvent.altKey) then mesh:Point(id).fSelected = false else mesh:Point(id).fSelected = true end else if (tryToPreserveSelection) then for _, mmesh in pairs(self.multiMeshes) do for i = 0, mmesh.mesh:CountPoints() - 1 do local point = mmesh.mesh:Point(i) point.fPrevSelected = point.fSelected point.fSelected = false end end self.multiSelectedPointsCount = 0 end local curveID = -1 local segID = -1 local didShape if (self.allowShapePicking) then -- try to pick a shape local mmesh, shape id, mmesh = next(self.multiMeshes) if (self.multiLayersCount == 1) and (moho.document:LayerAbsoluteID(moho.drawingLayer) + 1 == id) then -- sngl layer selected local shapeID = mouseEvent.view:PickShape(mouseEvent.pt) if (shapeID ~= -1) then shape = mmesh.mesh:Shape(shapeID) end else -- try Pick Globally mmesh = self.multiMeshes[moho.document:LayerAbsoluteID(mouseEvent.view:PickGlobalLayer(mouseEvent.pt)) + 1] shape = mouseEvent.view:PickGlobalShape(mouseEvent.pt) end if not (mmesh and shape) then -- else try Active layer priority mmesh = self.multiMeshes[moho.document:LayerAbsoluteID(moho.layer) + 1] local shapeID = mouseEvent.view:PickShape(mouseEvent.pt) if (shapeID ~= -1) then shape = mmesh.mesh:Shape(shapeID) else shape = nil end end if (mmesh and shape) then self.selMode = LM_SelectPoints.SELMODE_SHAPE for i = 0, shape:CountEdges() - 1 do curveID, segID = shape:GetEdge(i, curveID, segID) local curve = mmesh.mesh:Curve(curveID) if (mouseEvent.altKey) then curve:Point(segID).fSelected = false curve:Point(segID + 1).fSelected = false else curve:Point(segID).fSelected = true curve:Point(segID + 1).fSelected = true end end didShape = true end end if (not didShape) then layer, curveID, segID = mouseEvent.view:PickGlobalEdge(mouseEvent.pt, curveID, segID, self.mmeshPickWidth) -- ** local mmesh = layer and self.multiMeshes[moho.document:LayerAbsoluteID(layer) + 1] -- #SC Is Edge in Selected Layers? if (mmesh and curveID >= 0 and segID >= 0) then -- an edge was clicked on self.selMode = LM_SelectPoints.SELMODE_EDGE local curve = mmesh.mesh:Curve(curveID) -- new method - select the points in the curve that was clicked on if (mouseEvent.altKey) then local isCurveSelected = true for i = 0, curve:CountPoints() - 1 do if (not curve:Point(i).fSelected) then isCurveSelected = false break end end for i = 0, curve:CountPoints() - 1 do local point = curve:Point(i) if ((not isCurveSelected) or (point:CountCurves() < 2)) then point.fSelected = false if (point.fHidden) then point.fSelected = false end end end else for i = 0, curve:CountPoints() - 1 do local point = curve:Point(i) if (not point.fHidden) then point.fSelected = true end end end end end if (not allowEmptySelection) then local numSel = self:MultimeshCountSelectedPoints(moho, true) -- moho:CountSelectedPoints(true) if (numSel < 1) then for _, mmesh in pairs(self.multiMeshes) do for i = 0, mmesh.mesh:CountPoints() - 1 do local point = mmesh.mesh:Point(i) point.fSelected = point.fPrevSelected point.fPrevSelected = false end end end end if (tryToPreserveSelection) then local preserveSelection = false -- pass 1 - check if any of the selection is still selected for _, mmesh in pairs(self.multiMeshes) do for i = 0, mmesh.mesh:CountPoints() - 1 do local point = mmesh.mesh:Point(i) if (point.fPrevSelected and point.fSelected) then preserveSelection = true end end end -- pass 2 - preserve the selection if (preserveSelection) then for _, mmesh in pairs(self.multiMeshes) do for i = 0, mmesh.mesh:CountPoints() - 1 do local point = mmesh.mesh:Point(i) point.fSelected = point.fPrevSelected point.fPrevSelected = false end end else for _, mmesh in pairs(self.multiMeshes) do for i = 0, mmesh.mesh:CountPoints() - 1 do local point = mmesh.mesh:Point(i) point.fPrevSelected = false end end end end end self:MultimeshCountSelectedPoints(moho, true) if (mouseEvent.doubleClick) and (self.multiSelectedPointsCount > 0) then for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then moho:AddPointKeyframe(moho.drawingFrame, mmesh.layer, MOHO.MohoGlobals.EditMultipleKeys) end end end self.pivotOffset:Set(0, 0) -- #SC+ self.isPivotSet = false end function SS_MultiLayerTransformPoints:MultimeshSelectOnMouseUp(moho, mouseEvent) -- from LM_SelectPoints if (self.multiSelectedPointsCount == -1) then self:MultimeshCountSelectedPoints(moho, true) end self.allowShapePicking = true local lassoMode = false if (LM_SelectPoints.lassoMode) then if (not (LM_SelectPoints.ctrlKeySelection)) then lassoMode = true end else if (LM_SelectPoints.ctrlKeySelection) then lassoMode = true end end local mouseDist = math.abs(mouseEvent.pt.x - mouseEvent.startPt.x) + math.abs(mouseEvent.pt.y - mouseEvent.startPt.y) if (mouseDist < 8) then -- Single-click selection - select a shape or curve under the mouse self:MultimeshSelectSingleClickSelect(moho, mouseEvent, false, true) elseif (LM_SelectPoints.selMode == LM_SelectPoints.SELMODE_GROUP_PTS and lassoMode) then -- draw the finalized lasso outline local g = mouseEvent.view:Graphics() g:SetSmoothing(true) g:Push() local m = g:CurrentTransform() m:Invert() g:ApplyMatrix(m) g:SetColor(MOHO.MohoGlobals.SelCol) g:MoveTo(LM_SelectPoints.previousX, LM_SelectPoints.previousY) g:LineTo(mouseEvent.startPt.x, mouseEvent.startPt.y) g:Pop() g:SetSmoothing(false) mouseEvent.view:RefreshView() LM.Snooze(100) end LM_SelectPoints.isMouseDragging = false if (LM_SelectPoints.selMode == LM_SelectPoints.SELMODE_GROUP_PTS and self:MultimeshCountPoints(moho) > 0) then if (lassoMode) then local g = mouseEvent.view:Graphics() -- draw the lasso shape, and do hit testing -- 1 - draw the lasso shape local end1 = LM.Vector2:new_local() local end2 = LM.Vector2:new_local() g:Clear(0, 0, 0, 0) g:Push() local m = g:CurrentTransform() m:Invert() g:ApplyMatrix(m) g:SetColor(255, 255, 255, 255) g:BeginShape() for i = 1, #LM_SelectPoints.lassoList - 1 do end1:Set(LM_SelectPoints.lassoList[i][1], LM_SelectPoints.lassoList[i][2]) end2:Set(LM_SelectPoints.lassoList[i + 1][1], LM_SelectPoints.lassoList[i + 1][2]) g:AddLine(end1, end2) end end1:Set(LM_SelectPoints.lassoList[#LM_SelectPoints.lassoList][1], LM_SelectPoints.lassoList[#LM_SelectPoints.lassoList][2]) end2:Set(LM_SelectPoints.lassoList[1][1], LM_SelectPoints.lassoList[1][2]) g:AddLine(end1, end2) g:EndShape() g:Pop() -- test code to view the lasso's shape -- mouseEvent.view:RefreshView() -- LM.Snooze(1000) -- 2 - do hit testing on the lasso shape local v = LM.Vector2:new_local() local screenPt = LM.Point:new_local() -- local m = LM.Matrix:new_local() for _, mmesh in pairs(self.multiMeshes) do mmesh.layer:GetFullTransform(moho.frame, m, moho.document) for i = 0, mmesh.mesh:CountPoints() - 1 do local pt = mmesh.mesh:Point(i) if (not pt.fHidden) then v:Set(pt.fPos) m:Transform(v) g:WorldToScreen(v, screenPt) if (g:IsFullWhite(screenPt)) then if (mouseEvent.altKey) then pt.fSelected = false else pt.fSelected = true end end end end end else -- box select local v = LM.Vector2:new_local() local screenPt = LM.Point:new_local() local m = LM.Matrix:new_local() LM_SelectPoints.selRect:Normalize() for _, mmesh in pairs(self.multiMeshes) do mmesh.layer:GetFullTransform(moho.frame, m, moho.document) for i = 0, mmesh.mesh:CountPoints() - 1 do local pt = mmesh.mesh:Point(i) if (not pt.fHidden) then v:Set(pt.fPos) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, screenPt) if (LM_SelectPoints.selRect:Contains(screenPt)) then if (mouseEvent.altKey) then pt.fSelected = false else pt.fSelected = true end end end end end end end LM_SelectPoints.lassoList = nil -- moho:UpdateSelectedChannels() -- #SC Todo? self:MultimeshCountSelectedPoints(moho, true) end function SS_MultiLayerTransformPoints:OnMouseUp(moho, mouseEvent) self.allowShapePicking = true if (self.mode == self.MODE_SELECT) then mouseEvent.ctrlKey = false self:MultimeshSelectOnMouseUp(moho, mouseEvent) -- LM_SelectPoints:OnMouseUp(moho, mouseEvent) self.dragging = false self.selID = -1 mouseEvent.view:DrawMe() moho:UpdateUI() return end if (self.multiPointsCount < 1) then return end self.dragging = false if (self.mode == self.MODE_BEZIER) then -- bezier handle LM_Curvature:OnMouseUp(moho, mouseEvent) elseif (self.mode == self.MODE_PIVOT) then if (self.pivotOffset.x ~= 0 or self.pivotOffset.y ~= 0) then self.isPivotSet = true else self.isPivotSet = false end else -- if (self.mode ~= self.MODE_PIVOT) then moho:UpdateUI() if (self.mode == self.MODE_TRANS) then -- translate : don't modify the pivot elseif (self.mode == self.MODE_ROTATE) then -- rotate : move the pivot local v = self:MultimeshSelectedCenter(moho, true) self.pivotOffset = self.centerVec - v elseif (self.mode >= self.MODE_SCALE_) and (self.mode <= self.MODE_SCALE_MAX_) then -- scale : update the pivot if (self.isPivotSet) then self.pivotOffset = self.pivotCenterVec - self:MultimeshSelectedCenter(moho, true) else self.pivotOffset:Set(0, 0) end end end self.selID = -1 -- if (mouseEvent.pt.x == mouseEvent.startPt.x and mouseEvent.pt.y == mouseEvent.startPt.y) then local mouseDist = math.abs(mouseEvent.pt.x - mouseEvent.startPt.x) + math.abs(mouseEvent.pt.y - mouseEvent.startPt.y) if (mouseDist < 4) then -- #34389 - allow shift key to pass to select points so extended selections are possible -- mouseEvent.shiftKey = false mouseEvent.ctrlKey = false mouseEvent.altKey = false self:MultimeshSelectSingleClickSelect(moho, mouseEvent, false, true) -- sel from multlayer end moho:UpdateUI() end function SS_MultiLayerTransformPoints:OnKeyDown(moho, keyEvent) if (keyEvent.keyCode == LM.GUI.KEY_BIND) then -- Add Keyframe (no weld) for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then moho:AddPointKeyframe(moho.drawingFrame, mmesh.layer, MOHO.MohoGlobals.EditMultipleKeys) end end elseif ((keyEvent.keyCode == LM.GUI.KEY_DELETE) or (keyEvent.keyCode == LM.GUI.KEY_BACKSPACE)) then if (not self.dragging) then moho.document:PrepUndo() moho.document:SetDirty() for _, mmesh in pairs(self.multiMeshes) do MOHO.DeleteSelectedPoints(mmesh.mesh) end end elseif (keyEvent.keyCode == 9) or (keyEvent.altKey and ((keyEvent.keyCode == self.AltKeyCode1) or (keyEvent.keyCode == self.AltKeyCode2))) then -- tab -- Select connected glob" if (self.multiSelectedPointsCount > 0) then moho.document:PrepUndo() moho.document:SetDirty() self:MultimeshSelectConnected(moho) end elseif (keyEvent.keyCode == LM.GUI.KEY_ESCAPE) or (keyEvent.keyCode == 27) or (keyEvent.keyCode == self.AltKeyCode1) or (keyEvent.keyCode == self.AltKeyCode2) or (keyEvent.keyCode == LM.GUI.KEY_DESELECT) then -- Deselect All in Group if (self.multiSelectedPointsCount > 0) then moho.document:PrepUndo() moho.document:SetDirty() self:MultimeshSelectNone() end elseif (keyEvent.ctrlKey and keyEvent.altKey and (keyEvent.keyCode == 65 or keyEvent.keyCode == 97)) then -- A -- Select All in Group moho.document:PrepUndo() moho.document:SetDirty() self:MultimeshSelectAll(moho) elseif (keyEvent.ctrlKey) then -- nudge local pt1, pt2 = LM.Point:new_local(), LM.Point:new_local() local vc1, vc2 = LM.Vector2:new_local(), LM.Vector2:new_local() local inc = 1 if (keyEvent.shiftKey) then inc = 10 end pt1:Set(0, 0) moho.view:Graphics():ScreenToWorld(pt1, vc1) local function Nudge(xoff, yoff) moho.document:PrepUndo() for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:PrepMovePoints() end end pt2:Set(xoff, yoff) moho.view:Graphics():ScreenToWorld(pt2, vc2) self:MultimeshMovePoints(moho, vc2 - vc1) end if (keyEvent.keyCode == LM.GUI.KEY_UP) then Nudge(0, -inc) elseif (keyEvent.keyCode == LM.GUI.KEY_DOWN) then Nudge(0, inc) elseif (keyEvent.keyCode == LM.GUI.KEY_LEFT) then Nudge(-inc, 0) elseif (keyEvent.keyCode == LM.GUI.KEY_RIGHT) then Nudge(inc, 0) end end -- print(("KEY: Alt/Opt: %s, Ctrl/Cmd: %s, Shft: %s :: "):format(tostring(keyEvent.altKey), tostring(keyEvent.ctrlKey), tostring(keyEvent.shiftKey)), tostring(keyEvent.keyCode)) -- , " - ", keyEvent.key) keyEvent.view:DrawMe() moho:UpdateUI() end function SS_MultiLayerTransformPoints:OnInputDeviceEvent(moho, deviceEvent) if (self:MultimeshCountSelectedPoints(moho) < 1) then -- moho:CountSelectedPoints() < 1) then return false end -- #SC TODO -- if (deviceEvent.inputData:GetString("DeviceType") == "Wacom Multitouch") then -- local mtState = deviceEvent.inputData:GetInt("MultitouchState") -- if (mtState == 1) then -- first finger down -- self.mtFingersTouching = 0 -- we'll get the correct number on the next event -- self.mtTranslate = LM.Vector2:new_local() -- self.mtStartVec = LM.Vector2:new_local() -- self.mtAccumTranslate = LM.Vector2:new_local() -- self.mtScale = 1.0 -- self.mtStartScale = 1.0 -- self.mtAccumScale = 1.0 -- self.mtAngle = 0.0 -- self.mtStartAngle = 0.0 -- self.mtAccumAngle = 0.0 -- moho.document:SetDirty() -- moho.document:PrepUndo() -- self.numSel = self:MultimeshCountSelectedPoints(moho) -- moho:CountSelectedPoints() -- mesh:PrepMovePoints() -- if (self:UseFixedHandles(moho)) then -- mesh:PrepFixedHandles() -- end -- self.centerVec = self:MultimeshSelectedCenter(moho) -- self.centerVec = self.centerVec + self.pivotOffset -- self.mtTranslate:Set(0.0, 0.0) -- self.mtScale = 1.0 -- self.mtAngle = 0.0 -- elseif (mtState == 3) then -- last finger up -- self.mtFingersTouching = 0 -- moho:AddPointKeyframe(moho.drawingFrame, nil, MOHO.MohoGlobals.EditMultipleKeys) -- moho:NewKeyframe(CHANNEL_POINT) -- moho:UpdateUI() -- elseif (mtState == 2) then -- dragging -- local fingersTouching = deviceEvent.inputData:GetInt("FingersTouching") -- if (fingersTouching ~= self.mtFingersTouching) then -- self.mtAccumTranslate = self.mtAccumTranslate + self.mtTranslate -- self.mtAccumScale = self.mtAccumScale * self.mtScale -- self.mtAccumAngle = self.mtAccumAngle + self.mtAngle -- self.mtFingersTouching = fingersTouching -- self.mtStartVec = deviceEvent.inputData:GetVector2("MultitouchCenterVector") -- self.mtStartAngle = deviceEvent.inputData:GetFloat("MultitouchAngle") -- self.mtStartScale = deviceEvent.inputData:GetFloat("MultitouchScale") -- end -- if (deviceEvent.inputData:GetBool("DoubleTouch")) then -- if (fingersTouching == 2) then -- self:HandleMessage(moho, deviceEvent.view, self.RESET) -- if (frame ~= moho.frame) then -- moho:SetCurFrame(moho.frame) -- force a refresh when editing a key at a different frame -- end -- moho.document:DepthSort() -- end -- return true -- end -- self.mtTranslate = deviceEvent.inputData:GetVector2("MultitouchCenterVector") - self.mtStartVec -- if (deviceEvent.shiftKey) then -- if (math.abs(self.mtTranslate.x) > math.abs(self.mtTranslate.y)) then -- self.mtTranslate.y = 0 -- else -- self.mtTranslate.x = 0 -- end -- end -- self.mtScale = 1.0 -- self.mtAngle = 0.0 -- if (self.mtFingersTouching > 1) then -- self.mtAngle = deviceEvent.inputData:GetFloat("MultitouchAngle") - self.mtStartAngle -- self.mtScale = deviceEvent.inputData:GetFloat("MultitouchScale") / self.mtStartScale -- end -- mesh:TransformPoints(self.mtAccumTranslate + self.mtTranslate, self.mtAccumScale * self.mtScale, self.mtAccumScale * self.mtScale, self.mtAccumAngle + self.mtAngle, self.centerVec) -- if (self:UseFixedHandles(moho)) then -- mesh:PreserveHandlePositions() -- end -- moho:AddPointKeyframe(moho.drawingFrame) -- end -- return true -- end return false end function SS_MultiLayerTransformPoints:DrawMe(moho, view) if (moho:IsPlaying()) then return end if (self.lastSelectedCount ~= self:MultimeshCountSelectedPoints(moho)) then -- moho:CountSelectedPoints()) then self.lastSelectedCount = self:MultimeshCountSelectedPoints(moho) self.pivotOffset:Set(0, 0) self.isPivotSet = false end if (self.mode == self.MODE_SELECT and self.dragging) then LM_SelectPoints:DrawMe(moho, view) elseif (self.dragging and self.numSel == 1) then if (moho.drawingLayer:CurrentAction() ~= "" or moho:DisableDrawingTools()) then return -- welding in the middle of an action can lead to unexpected results end local g = view:Graphics() local matrix = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.frame, matrix, moho.document) g:Push() g:ApplyMatrix(matrix) if (self.endWeldToPoint) then g:SetColor(0, 255, 0, 128) else g:SetColor(255, 0, 0, 128) end g:SetSmoothing(true) g:SetBezierTolerance(2) g:FillCircle(self.endWeldVec, moho:PixelToDoc(self.autoWeldRadius) / g:CurrentScale(false)) g:SetSmoothing(false) g:Pop() elseif (not self.dragging or self.mode == self.MODE_PIVOT) then self.numSel = self:MultimeshCountSelectedPoints(moho) if (self.numSel >= 2) then local g = view:Graphics() local min = LM.Vector2:new_local() local max = LM.Vector2:new_local() local centerVec = LM.Vector2:new_local() local v = LM.Vector2:new_local() local vc1 = LM.ColorVector:new_local() local vc2 = LM.ColorVector:new_local() vc1:Set(MOHO.MohoGlobals.SelCol) vc2:Set(MOHO.MohoGlobals.BackCol) -- vc1 = (vc1 * 3 + vc2 * 4) / 7 vc1 = (vc1 + vc2) / 2 local col = vc1:AsColorStruct() local bbox = self:MultimeshSelectedMeshBounds(moho, moho.drawingFrame, view) min:Set(bbox.fMin.x, bbox.fMin.y) max:Set(bbox.fMax.x, bbox.fMax.y) -- moho.drawingLayer:GetFullTransform(moho.frame, matrix, moho.document) -- #SC pre-Trans g:Push() -- g:ApplyMatrix(matrix) g:SetColor(col) g:SetPenWidth(1) g:SetSmoothing(true) g:DrawLine(min.x, min.y, max.x, min.y) -- bigbox 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:SetPenWidth(1) local rotWidth = max.x - min.x if (max.y - min.y > rotWidth) then rotWidth = max.y - min.y end rotWidth = rotWidth * 0.1 g:DrawLine(min.x - rotWidth, min.y - rotWidth, min.x - rotWidth, max.y + rotWidth) -- outer g:DrawLine(min.x - rotWidth, max.y + rotWidth, max.x + rotWidth, max.y + rotWidth) g:DrawLine(max.x + rotWidth, max.y + rotWidth, max.x + rotWidth, min.y - rotWidth) g:DrawLine(max.x + rotWidth, min.y - rotWidth, min.x - rotWidth, min.y - rotWidth) g:SetPenWidth(2) v:Set(min.x, min.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(min.x, max.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(max.x, min.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(max.x, max.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set((min.x + max.x) / 2, min.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set((min.x + max.x) / 2, max.y) g:FrameCirclePixelRadius(v, self.markerR) v:Set(min.x, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR) v:Set(max.x, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR) g:SetPenWidth(1) -- Pivot if (self.dragging) then centerVec:Set(self.centerVec) else centerVec = self:MultimeshSelectedCenter(moho) centerVec = centerVec + self.pivotOffset end g:SetColor(col) g:SetSmoothing(true) g:DrawLine(centerVec.x - 0.05, centerVec.y, centerVec.x + 0.05, centerVec.y) g:DrawLine(centerVec.x, centerVec.y - 0.05, centerVec.x, centerVec.y + 0.05) v:Set(centerVec.x, centerVec.y) g:FrameCirclePixelRadius(v, self.markerR) g:Pop() elseif (self.dragging) then -- #SC end end -- Draw bezier handles if (self.showHandles) then local g = view:Graphics() local layerMatrix = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, layerMatrix, moho.document) g:Push() g:ApplyMatrix(layerMatrix) g:SetSmoothing(true) local selectedOnly = false if (self:MultimeshCountSelectedPoints(moho) < 2) then -- moho:CountSelectedPoints() < 2) then for _, mmesh in pairs(self.multiMeshes) do moho:LayerAsVector(mmesh.layer):DrawHandles(moho.document, g, selectedOnly) -- #SC Only works on Active layer end end g:Pop() end local g = view:Graphics() local m = LM.Matrix:new_local() -- #SC draw dem dots for _, mmesh in pairs(self.multiMeshes) do mmesh.layer:GetFullTransform(moho.frame, m, moho.document) g:Push() g:ApplyMatrix(m) for iPoint = 0, mmesh.mesh:CountPoints() - 1 do local point = mmesh.mesh:Point(iPoint) if not point.fHidden then if point.fSelected then g:SetColor(MOHO.MohoGlobals.SelCol) g:DrawDiamondMarker(point.fPos.x, point.fPos.y, 6) else g:SetColor(MOHO.MohoGlobals.ElemCol) g:DrawDiamondMarker(point.fPos.x, point.fPos.y, 4) end end end g:Pop() end -- #SC Show circ cross target @ pivot if (self.dragging) then g:Push() g:SetSmoothing(true) g:SetColor(MOHO.MohoGlobals.InacCol) -- g:SetColor(0, 0, 255, 255) g:DrawLine(self.pivotCenterVec.x - 0.01, self.pivotCenterVec.y, self.pivotCenterVec.x + 0.01, self.pivotCenterVec.y) g:DrawLine(self.pivotCenterVec.x, self.pivotCenterVec.y - 0.01, self.pivotCenterVec.x, self.pivotCenterVec.y + 0.01) g:FrameCirclePixelRadius(self.pivotCenterVec, self.markerR / 2) g:FrameCirclePixelRadius(self.pivotCenterVec, self.markerR) g:Pop() end end function SS_MultiLayerTransformPoints:WeldPoints(moho, view, dragging) -- if (moho.drawingLayer:CurrentAction() ~= "" or moho:DisableDrawingTools()) then -- return false -- welding in the middle of an action can lead to unexpected results -- end -- moho.document:SetDirty() -- -- try welding to the nearest point -- if (not dragging) then -- self.selID = -1 -- self.numSel = 0 -- for i = 0, mesh:CountPoints() - 1 do -- local pt = mesh:Point(i) -- if (pt.fSelected) then -- self.numSel = self.numSel + 1 -- self.selID = i -- if (self.numSel > 1) then -- break -- end -- end -- end -- if (self.numSel > 1) then -- self.selID = -1 -- end -- if (self.selID < 0) then -- return false -- end -- moho.document:PrepUndo() -- end -- if (self.selID < 0) then -- return false -- end -- local testVec1 = LM.Vector2:new_local() -- local testVec2 = LM.Vector2:new_local() -- testVec1:Set(mesh:Point(self.selID).fPos) -- local closestID = mesh:ClosestPoint(testVec1, self.selID) -- if (closestID < 0) then -- self.selID = -1 -- return false -- end -- testVec2:Set(mesh:Point(closestID).fPos) -- if (mesh:Point(self.selID).fHidden or mesh:Point(closestID).fHidden) then -- return false -- end -- -- convert the two chosen points to pixel coordinates -- -- this is to make sure that they are actually close enough in screen space -- local p1 = LM.Point:new_local() -- local p2 = LM.Point:new_local() -- local m = LM.Matrix:new_local() -- moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) -- m:Transform(testVec1) -- m:Transform(testVec2) -- view:Graphics():WorldToScreen(testVec1, p1) -- view:Graphics():WorldToScreen(testVec2, p2) -- p1.x = p1.x - p2.x -- p1.y = p1.y - p2.y -- closest = (p1.x * p1.x) + (p1.y * p1.y) -- if (closest < self.autoWeldRadius * self.autoWeldRadius) then -- found one close enough to weld -- if (mesh:ArePointsAdjacent(self.selID, closestID)) then -- -- this avoids welding adjacent points, particularly the end point of a curve to the previous point -- return true -- end -- if (mesh:WeldPoints(self.selID, closestID, moho.drawingLayerFrame)) then -- moho:Click() -- if (self.selID < closestID) then -- closestID = closestID - 1 -- end -- self.selID = -1 -- flag to end this interaction -- if ((self.autoFill or self.autoStroke) and (not mesh:ContinuousTriangulation())) then -- self:CreateShape(moho, mesh, closestID, self.autoFill) -- end -- end -- else -- return false -- end -- self.selID = -1 -- return true end function SS_MultiLayerTransformPoints:CreateShape(moho, mesh, ptID, filled) -- mesh:Point(ptID).fSelected = true -- mesh:SelectConnected() -- self.fillingShape = true -- moho.view:DrawMe() -- local shapeID = moho:CreateShape(filled, false, 0) -- self.fillingShape = false -- if (shapeID >= 0) then -- local shape = mesh:Shape(shapeID) -- shape.fSelected = true -- if (shape.fFillAllowed) then -- shape.fHasFill = self.autoFill -- end -- shape.fHasOutline = self.autoStroke -- moho:NewKeyframe(CHANNEL_FILL) -- moho:NewKeyframe(CHANNEL_LINE) -- moho:UpdateSelectedChannels() -- else -- self:MultimeshSelectNone() -- mesh:SelectNone() -- mesh:Point(ptID).fSelected = true -- end -- return shapeID end function SS_MultiLayerTransformPoints:UseFixedHandles(moho) if (not MOHO.IsMohoPro()) then return false end if (self.showHandles and self.fixedHandles) then -- and moho.drawingFrame == 0) then return true else return false end end -- ************************************************** -- Tool options - create and respond to tool's UI -- ************************************************** SS_MultiLayerTransformPoints.DUMMY = MOHO.MSG_BASE SS_MultiLayerTransformPoints.CHANGE = MOHO.MSG_BASE + 1 SS_MultiLayerTransformPoints.MODIFY_S = MOHO.MSG_BASE + 2 SS_MultiLayerTransformPoints.MODIFY_R = MOHO.MSG_BASE + 3 SS_MultiLayerTransformPoints.RESET = MOHO.MSG_BASE + 4 SS_MultiLayerTransformPoints.AUTOWELD = MOHO.MSG_BASE + 5 SS_MultiLayerTransformPoints.AUTOFILL = MOHO.MSG_BASE + 6 SS_MultiLayerTransformPoints.AUTOSTROKE = MOHO.MSG_BASE + 7 SS_MultiLayerTransformPoints.SHOWHANDLES = MOHO.MSG_BASE + 8 SS_MultiLayerTransformPoints.FIXEDHANDLES = MOHO.MSG_BASE + 9 SS_MultiLayerTransformPoints.FLIP_H = MOHO.MSG_BASE + 10 SS_MultiLayerTransformPoints.FLIP_V = MOHO.MSG_BASE + 11 SS_MultiLayerTransformPoints.SELECTITEM = MOHO.MSG_BASE + 12 SS_MultiLayerTransformPoints.autoWeld = false SS_MultiLayerTransformPoints.autoWeldRadius = 12 SS_MultiLayerTransformPoints.autoFill = false SS_MultiLayerTransformPoints.autoStroke = false SS_MultiLayerTransformPoints.showHandles = false SS_MultiLayerTransformPoints.fixedHandles = true SS_MultiLayerTransformPoints.ALIGN_ = MOHO.MSG_BASE + 20 SS_MultiLayerTransformPoints.ALIGN_LEFT = MOHO.MSG_BASE + 21 SS_MultiLayerTransformPoints.ALIGN_HORIZ = MOHO.MSG_BASE + 22 SS_MultiLayerTransformPoints.ALIGN_RIGHT = MOHO.MSG_BASE + 23 SS_MultiLayerTransformPoints.ALIGN_CENTER = MOHO.MSG_BASE + 24 SS_MultiLayerTransformPoints.ALIGN_TOP = MOHO.MSG_BASE + 25 SS_MultiLayerTransformPoints.ALIGN_VERT = MOHO.MSG_BASE + 26 SS_MultiLayerTransformPoints.ALIGN_BOT = MOHO.MSG_BASE + 27 SS_MultiLayerTransformPoints.ALIGN_MAX_ = MOHO.MSG_BASE + 29 function SS_MultiLayerTransformPoints:DoLayout(moho, layout) self.numSel = self:MultimeshCountSelectedPoints(moho, true) self.selCenterIsDirty = true self.menu = LM.GUI.Menu(MOHO.Localize("/Scripts/Tool/TransformPoints/SelectGroup=Select Group")) self.popup = LM.GUI.PopupMenu(120, false) self.popup:SetMenu(self.menu) layout:AddChild(self.popup) self.resetBut = LM.GUI.Button(MOHO.Localize("/Scripts/Tool/TransformPoints/Reset=Reset"), self.RESET) layout:AddChild(self.resetBut) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformPoints/Position=Position"))) self.textX = LM.GUI.TextControl(0, "00.000", self.CHANGE, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformPoints/X=X:")) self.textX:SetWheelInc(0.1) layout:AddChild(self.textX) self.textY = LM.GUI.TextControl(0, "00.000", self.CHANGE, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformPoints/Y=Y:")) self.textY:SetWheelInc(0.1) layout:AddChild(self.textY) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Scale=Scale"))) self.scaleX = LM.GUI.TextControl(0, "00.000", self.MODIFY_S, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformPoints/X=X:")) self.scaleX:SetWheelInc(0) layout:AddChild(self.scaleX) self.scaleY = LM.GUI.TextControl(0, "00.000", self.MODIFY_S, LM.GUI.FIELD_FLOAT, MOHO.Localize("/Scripts/Tool/TransformPoints/Y=Y:")) self.scaleY:SetWheelInc(0) layout:AddChild(self.scaleY) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Angle=Angle:"))) self.angle = LM.GUI.TextControl(0, "000.000", self.MODIFY_R, LM.GUI.FIELD_FLOAT) self.angle:SetWheelInc(0) layout:AddChild(self.angle) -- #SC self.autoWeldCheck = LM.GUI.CheckBox(MOHO.Localize("/Scripts/Tool/TransformPoints/AutoWeld=Auto-weld"), self.AUTOWELD) -- layout:AddChild(self.autoWeldCheck) -- self.autoFillCheck = LM.GUI.CheckBox(MOHO.Localize("/Scripts/Tool/TransformPoints/AutoFill=Auto-fill"), self.AUTOFILL) -- layout:AddChild(self.autoFillCheck) -- self.autoStrokeCheck = LM.GUI.CheckBox(MOHO.Localize("/Scripts/Tool/TransformPoints/AutoStroke=Auto-stroke"), self.AUTOSTROKE) -- layout:AddChild(self.autoStrokeCheck) -- if (MOHO.IsMohoPro()) then -- self.showHandleCheck = LM.GUI.ImageButton("ScriptResources/show_handles", MOHO.Localize("/Scripts/Tool/TransformPoints/ShowBezierHandles=Show Bezier Handles"), true, self.SHOWHANDLES, true) -- layout:AddChild(self.showHandleCheck) -- self.fixedHandleCheck = LM.GUI.ImageButton("ScriptResources/fixed_handles", MOHO.Localize("/Scripts/Tool/TransformPoints/FixedBezierHandles=Fixed Bezier Handles"), true, self.FIXEDHANDLES, true) -- layout:AddChild(self.fixedHandleCheck) -- end self.flipH = LM.GUI.ImageButton("ScriptResources/flip_points_h", MOHO.Localize("/Scripts/Tool/SelectPoints/FlipH=Flip Horizontally"), false, self.FLIP_H, true) layout:AddChild(self.flipH) self.flipV = LM.GUI.ImageButton("ScriptResources/flip_points_v", MOHO.Localize("/Scripts/Tool/SelectPoints/FlipV=Flip Vertically"), false, self.FLIP_V, true) layout:AddChild(self.flipV) -- #SC layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) -- | layout:AddChild(LM.GUI.StaticText("Align:")) self.alignLeftButton = LM.GUI.ImageButton("ScriptResources/ss_multi_layer_transform_points/ss_align_left", "Align Left", false, self.ALIGN_LEFT, true) layout:AddChild(self.alignLeftButton) self.alignHorzButton = LM.GUI.ImageButton("ScriptResources/ss_multi_layer_transform_points/ss_align_center_horiz", "Align Center Horizontally", false, self.ALIGN_HORIZ, true) layout:AddChild(self.alignHorzButton) self.alignRightButton = LM.GUI.ImageButton("ScriptResources/ss_multi_layer_transform_points/ss_align_right", "Align Right", false, self.ALIGN_RIGHT, true) layout:AddChild(self.alignRightButton) self.alignCntrButton = LM.GUI.ImageButton("ScriptResources/ss_multi_layer_transform_points/ss_align_center", "Align Centers", false, self.ALIGN_CENTER, true) layout:AddChild(self.alignCntrButton) self.alignTopButton = LM.GUI.ImageButton("ScriptResources/ss_multi_layer_transform_points/ss_align_top", "Align Top", false, self.ALIGN_TOP, true) layout:AddChild(self.alignTopButton) self.alignVertButton = LM.GUI.ImageButton("ScriptResources/ss_multi_layer_transform_points/ss_align_center_vert", "Align Center Vertically", false, self.ALIGN_VERT, true) layout:AddChild(self.alignVertButton) self.alignBottButton = LM.GUI.ImageButton("ScriptResources/ss_multi_layer_transform_points/ss_align_bottom", "Align Bottom", false, self.ALIGN_BOT, true) layout:AddChild(self.alignBottButton) end function SS_MultiLayerTransformPoints:UpdateWidgets(moho) if (moho:CurrentTool() ~= "SS_MultiLayerTransformPoints") then return -- this could get called when doing a double-tap on a multitouch Wacom device with a different active tool end -- MOHO.BuildGroupMenu(self.menu, mesh, self.SELECTITEM, self.DUMMY) --#SC todo local center = self:MultimeshSelectedCenter(moho) self.textX:SetValue(center.x) self.textY:SetValue(center.y) self.scaleX:SetValue(1) self.scaleY:SetValue(1) self.angle:SetValue(0) -- #SC -- if (MOHO.IsMohoPro()) then -- self.showHandleCheck:SetValue(self.showHandles) -- self.fixedHandleCheck:SetValue(self.fixedHandles) -- self.fixedHandleCheck:Enable(self.showHandles) -- end self.resetBut:Enable(moho.drawingFrame > 0) local isMultiSelect = self.multiSelectedPointsCount > 1 self.scaleX:Enable(isMultiSelect) self.scaleY:Enable(isMultiSelect) self.angle:Enable(isMultiSelect) self.flipH:Enable(isMultiSelect) self.flipV:Enable(isMultiSelect) self.alignLeftButton:Enable(isMultiSelect) self.alignHorzButton:Enable(isMultiSelect) self.alignRightButton:Enable(isMultiSelect) self.alignCntrButton:Enable(isMultiSelect) self.alignTopButton:Enable(isMultiSelect) self.alignVertButton:Enable(isMultiSelect) self.alignBottButton:Enable(isMultiSelect) end function SS_MultiLayerTransformPoints:HandleMessage(moho, view, msg) local v = LM.Vector2:new_local() local vec = LM.Vector2:new_local() local vec3 = LM.Vector3:new_local() local m = LM.Matrix:new_local() local mInv = LM.Matrix:new_local() local lVec = LM.Vector2:new_local() local offset = LM.Vector2:new_local() local angle local center, center3z, bbox = self:MultimeshSelectedCenter(moho, true) -- recount, bbox etc if (self.multiSelectedPointsCount > 0) then if (msg == self.CHANGE) then -- translate moho.document:PrepUndo() moho.document:SetDirty() offset.x = self.textX:FloatValue() - center.x offset.y = self.textY:FloatValue() - center.y self.pivotCenterVec:Set(center + offset) for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:PrepMovePoints() end end self:MultimeshMovePoints(moho, offset) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.MODIFY_S) then moho.document:PrepUndo() moho.document:SetDirty() local center3zOff = LM.Vector3:new_local() center3zOff:Set(center3z.x + self.pivotOffset.x, center3z.y + self.pivotOffset.y, center3z.z) self.pivotCenterVec:Set(center3zOff.x, center3zOff.y) local scaleX = self.scaleX:FloatValue() local scaleY = self.scaleY:FloatValue() self.scaleX:SetValue(1) self.scaleY:SetValue(1) local flip = false if (scaleX < 0.001) and (scaleY > 0.001) then flip = true elseif (scaleY < 0.001) and (scaleX > 0.001) then flip = true end for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then if (self:UseFixedHandles(moho)) then mmesh.mesh:PrepFixedHandles() end mmesh.mesh:PrepMovePoints() mmesh.layer:GetFullTransform(moho.frame, mInv, moho.document) mInv:Invert() lVec:Set(1, 0) mInv:Transform(lVec) angle = math.deg(math.atan2(lVec.y, lVec.x)) if ((angle > 45) and (angle < 135)) or ((angle < -45) and ((angle > -135))) then scaleX, scaleY = scaleY, scaleX end vec3:Set(center3zOff) mInv:Transform(vec3) vec:Set(vec3.x, vec3.y) mmesh.mesh:ScalePoints(scaleX, scaleY, vec, flip) moho:AddPointKeyframe(moho.frame, mmesh.layer, MOHO.MohoGlobals.EditMultipleKeys) if (self:UseFixedHandles(moho)) then mmesh.mesh:PreserveHandlePositions() end end end self.pivotOffset = self.pivotCenterVec - self:MultimeshSelectedCenter(moho, true) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.MODIFY_R) then moho.document:PrepUndo() moho.document:SetDirty() local center3zOff = LM.Vector3:new_local() center3zOff:Set(center3z.x + self.pivotOffset.x, center3z.y + self.pivotOffset.y, center3z.z) self.pivotCenterVec:Set(center3zOff.x, center3zOff.y) angle = math.rad(self.angle:FloatValue()) self.angle:SetValue(0) for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:PrepMovePoints() local _angle = angle if (mmesh.layer.fFlipH.value ~= mmesh.layer.fFlipV.value) then _angle = -_angle end mmesh.layer:GetFullTransform(moho.frame, mInv, moho.document) mInv:Invert() vec3:Set(center3zOff) mInv:Transform(vec3) vec:Set(vec3.x, vec3.y) mmesh.mesh:RotatePoints(_angle, vec) moho:AddPointKeyframe(moho.frame, mmesh.layer, MOHO.MohoGlobals.EditMultipleKeys) if (self:UseFixedHandles(moho)) then mmesh.mesh:PreserveHandlePositions() end end end self.pivotOffset = self.pivotCenterVec - self:MultimeshSelectedCenter(moho, true) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.FLIP_H) or (msg == self.FLIP_V) then if (self.multiSelectedPointsCount > 1) then moho.document:PrepUndo() moho.document:SetDirty() center3z.x, center3z.y = center3z.x + self.pivotOffset.x, center3z.y + self.pivotOffset.y for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:PrepMovePoints() mmesh.layer:GetFullTransform(moho.frame, m, moho.document) mInv:Set(m) mInv:Invert() for i = 0, mmesh.mesh:CountPoints() - 1 do local pt = mmesh.mesh:Point(i) if (pt.fSelected) then vec3:Set(pt.fPos.x, pt.fPos.y, 0) m:Transform(vec3) -- > wrld if (msg == self.FLIP_H) then vec3.x = center3z.x + center3z.x - vec3.x else -- > self.FLIP_V vec3.y = (2 * center3z.y) - vec3.y end mInv:Transform(vec3) pt.fPos:Set(vec3.x, vec3.y) pt:FlipControlHandles(moho.drawingFrame) end end moho:AddPointKeyframe(moho.drawingFrame, mmesh.layer) mmesh.layer:UpdateCurFrame() end end v:Set(center3z.x, center3z.y) self.pivotOffset = v - self:MultimeshSelectedCenter(moho, true) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() end elseif (msg == self.RESET) then if (moho.drawingFrame > 0) then moho.document:PrepUndo() moho.document:SetDirty() for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:PrepMovePoints() for i = 0, mmesh.mesh:CountPoints() - 1 do local pt = mmesh.mesh:Point(i) if (pt.fSelected) then pt:SetPos(pt.fAnimPos:GetValue(0), moho.drawingLayerFrame) end end moho:AddPointKeyframe(moho.drawingFrame, mmesh.layer, false) end end end self:UpdateWidgets(moho) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg > self.ALIGN_) and (msg <= self.ALIGN_MAX_) then moho.document:PrepUndo() moho.document:SetDirty() local xloc, yloc if (msg == self.ALIGN_LEFT) then xloc = bbox.fMin.x elseif (msg == self.ALIGN_HORIZ) then xloc = center.x elseif (msg == self.ALIGN_RIGHT) then xloc = bbox.fMax.x elseif (msg == self.ALIGN_CENTER) then xloc, yloc = center.x, center.y elseif (msg == self.ALIGN_TOP) then yloc = bbox.fMax.y -- dn/up elseif (msg == self.ALIGN_VERT) then yloc = center.y elseif (msg == self.ALIGN_BOT) then yloc = bbox.fMin.y -- up/dn end self.pivotCenterVec:Set(xloc or center.x, yloc or center.y) for _, mmesh in pairs(self.multiMeshes) do if (mmesh.selectedPointsCount > 0) then mmesh.mesh:PrepMovePoints() if (self:UseFixedHandles(moho)) then mmesh.mesh:PrepFixedHandles() end mmesh.layer:GetFullTransform(moho.frame, m, moho.document) mInv:Set(m) mInv:Invert() for i = 0, mmesh.mesh:CountPoints() - 1 do local pt = mmesh.mesh:Point(i) if (pt.fSelected) then vec3:Set(pt.fPos.x, pt.fPos.y, 0) m:Transform(vec3) vec3.x, vec3.y = xloc or vec3.x, yloc or vec3.y mInv:Transform(vec3) pt.fPos:Set(vec3.x, vec3.y) end end moho:AddPointKeyframe(moho.drawingFrame, mmesh.layer, true) if (self:UseFixedHandles(moho)) then mmesh.mesh:PreserveHandlePositions() end end end moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() end self:MultimeshSelectedCenter(moho, true) end -- if (msg == self.AUTOWELD) then -- -- #SC self.autoWeld = self.autoWeldCheck:Value() -- elseif (msg == self.AUTOFILL) then -- -- #SC self.autoFill = self.autoFillCheck:Value() -- elseif (msg == self.AUTOSTROKE) then -- -- #SC self.autoStroke = self.autoStrokeCheck:Value() -- elseif (msg == self.SHOWHANDLES) then -- -- #SC if (MOHO.IsMohoPro()) then -- -- self.showHandles = self.showHandleCheck:Value() -- -- moho:UpdateUI() -- -- end -- elseif (msg == self.FIXEDHANDLES) then -- -- #SC if (MOHO.IsMohoPro()) then -- -- self.fixedHandles = self.fixedHandleCheck:Value() -- -- end -- elseif (msg >= self.SELECTITEM) then -- -- #SC mesh:SelectNone() -- -- local i = msg - self.SELECTITEM -- -- local name = mesh:Group(i):Name() -- -- mesh:SelectGroup(name) -- -- moho:UpdateUI() -- end end
SS - Multi Layer Transform Points
Listed
Author: simplsam
View Script
Script type: Tool
Uploaded: Jun 04 2023, 05:42
Last modified: Jun 05 2023, 12:44
Script Version: 10+01.04 #5306
Quickly Select & Transform multiple points across multiple selected layer groups (ver +1.04)
SS Multi-Layer Transform Points is a convenience tool which allows you to quickly transform selected points across multiple selected layers. The tool was developed as an addition to the existing built-in Transform Points tool, and does not replace it, but allows you to select, move, scale and rotate selected points on multiple layers at the same time, or simply select child-content layers from one or more groups of layers - without having to leave the currently selected groups/layers.
Enhanced Features:
- Multi-Layer points visibility & editing - if the layer is selected, or the layer is a child of a selected group layer
- Proximity based Select or Transform
- Scale & Flip can use pivot offset
- Nearest (single) point manipulation - across all selected layers
- Global Shape, Edge and Bounding Box selection - across all selected layers
- Does not create static-keyframe during a simple single-click selection / deselection
- Can add static-keyframe using double-click selection, or keyboard [Enter] with selected points
- Align points to other points - left, mid-l/r, right, middles, top, mid-t/b, bottom
- The Transformation bounding box is always upright rectangular (does not rotate with layer)
- Use Ctrl-Alt-A to select all points on all selected layers / groups of layers
- Eight angular-points of fixed rotation (when using the Rotation Shift modifier)
It should otherwise be very similarly to the built-in Transform Points tool.
Video Demo:
Tool Options:
The tool has 4 main modes of operation - plus flip & point alignment, all working with multiple-layers
1. Select
Single or multiple Points/Shapes/Edges can be selected by single-click, drag / ctrl-drag or ctrl-alt-a (select all). You can ctrl-shift-click to add individual points to selection, or you can shift-click Shapes or Edges to add them to selection. Esc or single-click canvas background to deselect. All point selection actions will be limited to content in the currently selected Groups and Layers.
2. Translate
Used to move a single or groups of selected Points. This can be achieved via numerical entry, or using the mouse to drag the selection, or by using ctrl-[up/down/left/right] to nudge the selected points. If zero points are selected the tools will automatically switch between Select and Transform mode - based on point proximity. If 1 points are already selected, the one-click select will choose the nearest point to the mouse - so you can easily drag the nearest point.
3.Scale
Used to scale & resize the group of selected Points. Drag side-handles (Top / Bottom / Left / Right) to stretch with pivot anchor at the opposite side, or alt-drag side-handles to stretch uniformly from center. Drag corner-handles to uniformly scale to the opposite corner, or shift-drag corner-handles to freeform scale from the opposite corner. You can also move the Pivot point to scale (in any of the above modes) towards that pivot location.
4. Rotate
Drag between the inner and outer bounding box guide lines to rotate the selection about the pivot point. Shift-drag allows you to rotate in 8 fixed 45° increments. You can also drag and move the pivot point to change the pivot point of rotation.
5. Flip & Align
Allows you to Flip points Horizontally and Vertically about the center or about the pivot point, and Align selected points Left, mid-Left/Right, Right, Centers, Top, mid-Top/Bottom & Bottom.
For the most part the tool behaves like the built-in Transform Points tool, so you can refer to the docs for that for further options.
So … Why do you need the Multi-Layer Transform Points tool?
Speed and convenience. The addon can enhance your animation and point manipulation workflow. Particularly handy when wishing to maintain point and shape alignment across different layers, but also handy for selecting or picking content on different layers without having to change the currently selected layers.
Version:
- version: 01.04 #530605 MH12.5+
- release: 10.0+1.04 (based on LM Transform Points 10.0)
- by Sam Cogheil (SimplSam)
How do I get set up ?
To install:
- Use the Moho ‘Scripts’ > ‘Install Script …’ menu (after you Download for Install Script, and extract the zip files)
To use:
- Run the Multi-Layer Transform Points tool from the Tools palette
- The tool will be invoked allowing you to manipulate the vector points of your animation content
- You can select multiple vector layers and/or multiple parent group layers to enable them for editing
Notes & Limitations
Notes:
- Compatible with MH12.5+
Known Limitations:
- Construction curves are only visible on the Active layer (last selected), but can be turned on manually using layer quick-properties
- Point Welding across multiple layers is not possible, thus the feature (as a whole) is not supported
- Bezier Handles would only be visible on a single-selected layer, thus they are not currently supported
- Copy/Paste only works from and to the Active (last selected) layer - if it is a vector layer
- Point Groups are not currently supported
- Some odd point placement / behaviour may occur with:
- Switch layers & Frame by Frame content layers – so they are not officially supported
- Scaling of content on rotated layers which are not rotated close to 0, 90, 180 or 270 degrees
- 3D translated layers (i.e. Rotated about X or Y axis) and Sheared layers
Special Thanks to:
- Stan (and the team): MOHO Scripting – https://mohoscripting.com
- The friendly faces @ Lost Marble Moho forum – https://www.lostmarble.com/forum/
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: 1086
SS - Multi Layer Transform Points
Listed
Author: simplsam
View Script
Script type: Tool
Uploaded: Jun 04 2023, 05:42
Last modified: Jun 05 2023, 12:44
Script Version: 10+01.04 #5306
Quickly Select & Transform multiple points across multiple selected layer groups (ver +1.04)
SS Multi-Layer Transform Points is a convenience tool which allows you to quickly transform selected points across multiple selected layers. The tool was developed as an addition to the existing built-in Transform Points tool, and does not replace it, but allows you to select, move, scale and rotate selected points on multiple layers at the same time, or simply select child-content layers from one or more groups of layers - without having to leave the currently selected groups/layers.
Enhanced Features:
- Multi-Layer points visibility & editing - if the layer is selected, or the layer is a child of a selected group layer
- Proximity based Select or Transform
- Scale & Flip can use pivot offset
- Nearest (single) point manipulation - across all selected layers
- Global Shape, Edge and Bounding Box selection - across all selected layers
- Does not create static-keyframe during a simple single-click selection / deselection
- Can add static-keyframe using double-click selection, or keyboard [Enter] with selected points
- Align points to other points - left, mid-l/r, right, middles, top, mid-t/b, bottom
- The Transformation bounding box is always upright rectangular (does not rotate with layer)
- Use Ctrl-Alt-A to select all points on all selected layers / groups of layers
- Eight angular-points of fixed rotation (when using the Rotation Shift modifier)
It should otherwise be very similarly to the built-in Transform Points tool.
Video Demo:
Tool Options:
The tool has 4 main modes of operation - plus flip & point alignment, all working with multiple-layers
1. Select
Single or multiple Points/Shapes/Edges can be selected by single-click, drag / ctrl-drag or ctrl-alt-a (select all). You can ctrl-shift-click to add individual points to selection, or you can shift-click Shapes or Edges to add them to selection. Esc or single-click canvas background to deselect. All point selection actions will be limited to content in the currently selected Groups and Layers.
2. Translate
Used to move a single or groups of selected Points. This can be achieved via numerical entry, or using the mouse to drag the selection, or by using ctrl-[up/down/left/right] to nudge the selected points. If zero points are selected the tools will automatically switch between Select and Transform mode - based on point proximity. If 1 points are already selected, the one-click select will choose the nearest point to the mouse - so you can easily drag the nearest point.
3.Scale
Used to scale & resize the group of selected Points. Drag side-handles (Top / Bottom / Left / Right) to stretch with pivot anchor at the opposite side, or alt-drag side-handles to stretch uniformly from center. Drag corner-handles to uniformly scale to the opposite corner, or shift-drag corner-handles to freeform scale from the opposite corner. You can also move the Pivot point to scale (in any of the above modes) towards that pivot location.
4. Rotate
Drag between the inner and outer bounding box guide lines to rotate the selection about the pivot point. Shift-drag allows you to rotate in 8 fixed 45° increments. You can also drag and move the pivot point to change the pivot point of rotation.
5. Flip & Align
Allows you to Flip points Horizontally and Vertically about the center or about the pivot point, and Align selected points Left, mid-Left/Right, Right, Centers, Top, mid-Top/Bottom & Bottom.
For the most part the tool behaves like the built-in Transform Points tool, so you can refer to the docs for that for further options.
So … Why do you need the Multi-Layer Transform Points tool?
Speed and convenience. The addon can enhance your animation and point manipulation workflow. Particularly handy when wishing to maintain point and shape alignment across different layers, but also handy for selecting or picking content on different layers without having to change the currently selected layers.
Version:
- version: 01.04 #530605 MH12.5+
- release: 10.0+1.04 (based on LM Transform Points 10.0)
- by Sam Cogheil (SimplSam)
How do I get set up ?
To install:
- Use the Moho ‘Scripts’ > ‘Install Script …’ menu (after you Download for Install Script, and extract the zip files)
To use:
- Run the Multi-Layer Transform Points tool from the Tools palette
- The tool will be invoked allowing you to manipulate the vector points of your animation content
- You can select multiple vector layers and/or multiple parent group layers to enable them for editing
Notes & Limitations
Notes:
- Compatible with MH12.5+
Known Limitations:
- Construction curves are only visible on the Active layer (last selected), but can be turned on manually using layer quick-properties
- Point Welding across multiple layers is not possible, thus the feature (as a whole) is not supported
- Bezier Handles would only be visible on a single-selected layer, thus they are not currently supported
- Copy/Paste only works from and to the Active (last selected) layer - if it is a vector layer
- Point Groups are not currently supported
- Some odd point placement / behaviour may occur with:
- Switch layers & Frame by Frame content layers – so they are not officially supported
- Scaling of content on rotated layers which are not rotated close to 0, 90, 180 or 270 degrees
- 3D translated layers (i.e. Rotated about X or Y axis) and Sheared layers
Special Thanks to:
- Stan (and the team): MOHO Scripting – https://mohoscripting.com
- The friendly faces @ Lost Marble Moho forum – https://www.lostmarble.com/forum/
Enhanced Features:
- Multi-Layer points visibility & editing - if the layer is selected, or the layer is a child of a selected group layer
- Proximity based Select or Transform
- Scale & Flip can use pivot offset
- Nearest (single) point manipulation - across all selected layers
- Global Shape, Edge and Bounding Box selection - across all selected layers
- Does not create static-keyframe during a simple single-click selection / deselection
- Can add static-keyframe using double-click selection, or keyboard [Enter] with selected points
- Align points to other points - left, mid-l/r, right, middles, top, mid-t/b, bottom
- The Transformation bounding box is always upright rectangular (does not rotate with layer)
- Use Ctrl-Alt-A to select all points on all selected layers / groups of layers
- Eight angular-points of fixed rotation (when using the Rotation Shift modifier)
It should otherwise be very similarly to the built-in Transform Points tool.
Video Demo:
Tool Options:
The tool has 4 main modes of operation - plus flip & point alignment, all working with multiple-layers
1. Select
Single or multiple Points/Shapes/Edges can be selected by single-click, drag / ctrl-drag or ctrl-alt-a (select all). You can ctrl-shift-click to add individual points to selection, or you can shift-click Shapes or Edges to add them to selection. Esc or single-click canvas background to deselect. All point selection actions will be limited to content in the currently selected Groups and Layers.
2. Translate
Used to move a single or groups of selected Points. This can be achieved via numerical entry, or using the mouse to drag the selection, or by using ctrl-[up/down/left/right] to nudge the selected points. If zero points are selected the tools will automatically switch between Select and Transform mode - based on point proximity. If 1 points are already selected, the one-click select will choose the nearest point to the mouse - so you can easily drag the nearest point.
3.Scale
Used to scale & resize the group of selected Points. Drag side-handles (Top / Bottom / Left / Right) to stretch with pivot anchor at the opposite side, or alt-drag side-handles to stretch uniformly from center. Drag corner-handles to uniformly scale to the opposite corner, or shift-drag corner-handles to freeform scale from the opposite corner. You can also move the Pivot point to scale (in any of the above modes) towards that pivot location.
4. Rotate
Drag between the inner and outer bounding box guide lines to rotate the selection about the pivot point. Shift-drag allows you to rotate in 8 fixed 45° increments. You can also drag and move the pivot point to change the pivot point of rotation.
5. Flip & Align
Allows you to Flip points Horizontally and Vertically about the center or about the pivot point, and Align selected points Left, mid-Left/Right, Right, Centers, Top, mid-Top/Bottom & Bottom.
For the most part the tool behaves like the built-in Transform Points tool, so you can refer to the docs for that for further options.
So … Why do you need the Multi-Layer Transform Points tool?
Speed and convenience. The addon can enhance your animation and point manipulation workflow. Particularly handy when wishing to maintain point and shape alignment across different layers, but also handy for selecting or picking content on different layers without having to change the currently selected layers.
Version:
- version: 01.04 #530605 MH12.5+
- release: 10.0+1.04 (based on LM Transform Points 10.0)
- by Sam Cogheil (SimplSam)
How do I get set up ?
To install:
- Use the Moho ‘Scripts’ > ‘Install Script …’ menu (after you Download for Install Script, and extract the zip files)
To use:
- Run the Multi-Layer Transform Points tool from the Tools palette
- The tool will be invoked allowing you to manipulate the vector points of your animation content
- You can select multiple vector layers and/or multiple parent group layers to enable them for editing
Notes & Limitations
Notes:
- Compatible with MH12.5+
Known Limitations:
- Construction curves are only visible on the Active layer (last selected), but can be turned on manually using layer quick-properties
- Point Welding across multiple layers is not possible, thus the feature (as a whole) is not supported
- Bezier Handles would only be visible on a single-selected layer, thus they are not currently supported
- Copy/Paste only works from and to the Active (last selected) layer - if it is a vector layer
- Point Groups are not currently supported
- Some odd point placement / behaviour may occur with:
- Switch layers & Frame by Frame content layers – so they are not officially supported
- Scaling of content on rotated layers which are not rotated close to 0, 90, 180 or 270 degrees
- 3D translated layers (i.e. Rotated about X or Y axis) and Sheared layers
Special Thanks to:
- Stan (and the team): MOHO Scripting – https://mohoscripting.com
- The friendly faces @ Lost Marble Moho forum – https://www.lostmarble.com/forum/
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: 1086