-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "LK_TransformPoints" -- ************************************************** -- General information about this script -- ************************************************** LK_TransformPoints = {} LK_TransformPoints.BASE_STR = 2375 function LK_TransformPoints:Name() return "Transform Points" end function LK_TransformPoints:Version() return "1.1 based on 10.0" end function LK_TransformPoints:IsBeginnerScript() return true end function LK_TransformPoints:Description() return string.format( MOHO.Localize("/Scripts/Tool/TransformPoints/Description=Move/Scale/Rotate selected points (press <%s> to weld, hold <shift> to constrain, <alt> to disable auto-welding, <alt> to scale to center, <shift> while scaling to squash, <ctrl/cmd> to select points)"), MOHO.BindingKeyName() ) end function LK_TransformPoints:BeginnerDescription() return MOHO.Localize("/Scripts/Tool/TransformPoints/BeginnerDescription=Click in the center of your object to select all points, allowing you to move the entire object. If you only select and drag one point or multiple points, you can distort the object. Move points around in time to animate them.") end function LK_TransformPoints:BeginnerDisabledDescription() return MOHO.Localize("/Scripts/Tool/TransformPoints/BeginnerDisabledDescription=You need to create a vector drawing on a Vector Layer first with the 'Add Point', 'Freehand' or 'Draw Shape' tool before being able to use this tool. To add a new vector layer, go to the Layers window and select New Layer > Vector.") end function LK_TransformPoints:Creator() return "Lost Marble LLC Lukas mod" end function LK_TransformPoints:ColorizeIcon() return true end function LK_TransformPoints:UILabel() return(MOHO.Localize("/Scripts/Tool/TransformPoints/TransformPoints=Transform Points")) end function LK_TransformPoints:LoadPrefs(prefs) self.autoWeld = prefs:GetBool("LK_TransformPoints.autoWeld", false) self.autoFill = prefs:GetBool("LK_TransformPoints.autoFill", false) self.autoStroke = prefs:GetBool("LK_TransformPoints.autoStroke", false) self.showHandles = prefs:GetBool("LK_TransformPoints.showHandles", false) self.fixedHandles = prefs:GetBool("LK_TransformPoints.fixedHandles", false) end function LK_TransformPoints:SavePrefs(prefs) prefs:SetBool("LK_TransformPoints.autoWeld", self.autoWeld) prefs:SetBool("LK_TransformPoints.autoFill", self.autoFill) prefs:SetBool("LK_TransformPoints.autoStroke", self.autoStroke) prefs:SetBool("LK_TransformPoints.showHandles", self.showHandles) prefs:SetBool("LK_TransformPoints.fixedHandles", self.fixedHandles) end function LK_TransformPoints:ResetPrefs() LK_TransformPoints.autoWeld = false LK_TransformPoints.autoWeldRadius = 12 LK_TransformPoints.autoFill = false LK_TransformPoints.autoStroke = false LK_TransformPoints.showHandles = false LK_TransformPoints.fixedHandles = true end function LK_TransformPoints:NonDragMouseMove() return true -- Call MouseMoved() even if the mouse button is not down end -- ************************************************** -- Recurring values -- ************************************************** LK_TransformPoints.dragging = false LK_TransformPoints.keyMovement = false LK_TransformPoints.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 LK_TransformPoints.numSel = 0 LK_TransformPoints.selID = -1 LK_TransformPoints.fillingShape = false LK_TransformPoints.endWeldVec = LM.Vector2:new_local() LK_TransformPoints.endWeldVec:Set(-10000000, -10000000) LK_TransformPoints.endWeldToPoint = true LK_TransformPoints.startAngle = 0 LK_TransformPoints.lastVec = LM.Vector2:new_local() LK_TransformPoints.lastSelectedCount = 0 LK_TransformPoints.pivotOffset = LM.Vector2:new_local() LK_TransformPoints.selectMode = 100 LK_TransformPoints.markerR = 8 -- ************************************************** -- The guts of this script -- ************************************************** function LK_TransformPoints:IsEnabled(moho) if (moho:CountPoints() > 0) then return true end return false end function LK_TransformPoints:IsRelevant(moho) if MohoMode ~= nil then if MohoMode.vanilla then return false end end local mesh = moho:DrawingMesh() if (mesh == nil) then return false end return true end function LK_TransformPoints:SelectedMeshBounds(moho, layer, mesh, frame, view) local bbox = LM.BBox:new_local() local min = LM.Vector2:new_local() local max = LM.Vector2:new_local() mesh:SelectedBounds(min, max) bbox.fMin:Set(min.x, min.y, 0) bbox.fMax:Set(max.x, max.y, 0) -- 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 if (xLen < yLen / 10.0) then local 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 local 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 m = LM.Matrix:new_local() local v = LM.Vector2:new_local() local pt1 = LM.Point:new_local() local pt2 = LM.Point:new_local() layer:GetFullTransform(frame, m, moho.document) v:Set(bbox.fMin.x, bbox.fMin.y) m:Transform(v) view:Graphics():WorldToScreen(v, pt1) v:Set(bbox.fMax.x, bbox.fMax.y) m:Transform(v) 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 LK_TransformPoints:TestMousePoint(moho, mouseEvent) -- Returns what mode the tool would be in if the user clicked at the current mouse location if (self.keyMovement) then return 0 end local mesh = moho:DrawingMesh() if (mesh == nil) then return 0 end self.numSel = moho:CountSelectedPoints() if (self.numSel < 2) then return 0 end local bbox = self:SelectedMeshBounds(moho, moho.drawingLayer, mesh, moho.drawingFrame, mouseEvent.view) local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local m = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) -- test for uniform scaling v:Set(bbox.fMin.x, bbox.fMin.y) m:Transform(v) 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 -- bottom left return 4 end v:Set(bbox.fMin.x, bbox.fMax.y) m:Transform(v) 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 -- top left return 2 end v:Set(bbox.fMax.x, bbox.fMax.y) m:Transform(v) 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 -- top right return 3 end v:Set(bbox.fMax.x, bbox.fMin.y) m:Transform(v) 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 -- bottom right return 5 end -- test for X scaling v:Set(bbox.fMin.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) 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 -- left return 6 end v:Set(bbox.fMax.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) 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 -- right return 7 end -- test for Y scaling v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y) m:Transform(v) 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 -- bottom return 9 end v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y) m:Transform(v) 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 -- top return 8 end -- test for pivot point if (self.dragging) then v:Set(self.centerVec) else v = mesh:SelectedCenter() v = v + self.pivotOffset end m:Transform(v) 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 -- pivot point return 11 end -- test for translation outside the bounding box 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 (mouseEvent.drawingVec.x < bbox.fMin.x - rotWidth or mouseEvent.drawingVec.x > bbox.fMax.x + rotWidth or mouseEvent.drawingVec.y < bbox.fMin.y - rotWidth or mouseEvent.drawingVec.y > bbox.fMax.y + rotWidth) then return 0 end -- test for rotation if (mouseEvent.drawingVec.x < bbox.fMin.x or mouseEvent.drawingVec.x > bbox.fMax.x or mouseEvent.drawingVec.y < bbox.fMin.y or mouseEvent.drawingVec.y > bbox.fMax.y) then return 1 end return 0 -- translation inside the bounding box end function LK_TransformPoints:OnMouseDown(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end self.dragging = true self.endWeldVec:Set(-10000000, -10000000) self.centerVec = mesh:SelectedCenter() self.centerVec = self.centerVec + self.pivotOffset self.startPivotOffset = LM.Vector2:new_local() self.startPivotOffset:Set(self.pivotOffset) self.mode = self:TestMousePoint(moho, mouseEvent) if (mouseEvent.ctrlKey) then self.mode = self.selectMode mouseEvent.ctrlKey = false LM_SelectPoints:OnMouseDown(moho, mouseEvent) return end self.selectedMin = LM.Vector2:new_local() self.selectedMax = LM.Vector2:new_local() mesh:SelectedBounds(self.selectedMin, self.selectedMax) moho.document:SetDirty() self.numSel = moho:CountSelectedPoints() 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 == 0 and self.numSel < 2 and self.showHandles) then LM_Curvature:TestForClosestHandle(moho, mouseEvent) if (LM_Curvature.selID >= 0 and LM_Curvature.handleSide ~= 0) then -- a bezier handle was selected self.mode = 10 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 = 0 end end end self.selID = -1 self.handleSide = 0 end if (self.mode ~= 11) then moho.document:PrepUndo(moho.drawingLayer) end end if (self.mode == 0) then -- translate if (self.selID == -1) then local shiftKey = mouseEvent.shiftKey local ctrlKey = mouseEvent.ctrlKey local altKey = mouseEvent.altKey mouseEvent.shiftKey = false mouseEvent.ctrlKey = false mouseEvent.altKey = false mouseEvent.shiftKey = altKey mouseEvent.ctrlKey = altKey mouseEvent.altKey = altKey self.numSel = moho:CountSelectedPoints(true) if (self.numSel < 2) then -- move just a single point -- find the closest point here self.selID = mesh:ClosestPoint(mouseEvent.drawingStartVec) if (self.selID >= 0) then self.numSel = 1 mesh:SelectNone() mesh:Point(self.selID).fSelected = true moho:UpdateSelectedChannels() end else self.selID = mesh:ClosestPoint(mouseEvent.drawingStartVec) end end elseif (self.mode == 1) then -- rotate local shiftKey = mouseEvent.shiftKey local ctrlKey = mouseEvent.ctrlKey local altKey = mouseEvent.altKey mouseEvent.shiftKey = false mouseEvent.ctrlKey = false mouseEvent.altKey = false mouseEvent.shiftKey = altKey mouseEvent.ctrlKey = altKey mouseEvent.altKey = altKey self.numSel = moho:CountSelectedPoints(true) self.startAngle = 0 self.lastVec:Set(mouseEvent.drawingVec) elseif (self.mode == 10) then -- bezier handle LM_Curvature:OnMouseDown(moho, mouseEvent) return elseif (self.mode == 11) then -- pivot point self.numSel = moho:CountSelectedPoints(true) self.lastVec:Set(mouseEvent.drawingVec) else -- scale self.lastScaleX = 1.0 self.lastScaleY = 1.0 if (self.numSel < 2) then local shiftKey = mouseEvent.shiftKey local ctrlKey = mouseEvent.ctrlKey local altKey = mouseEvent.altKey mouseEvent.shiftKey = false mouseEvent.ctrlKey = false mouseEvent.altKey = false mouseEvent.shiftKey = altKey mouseEvent.ctrlKey = altKey mouseEvent.altKey = altKey self.numSel = moho:CountSelectedPoints(true) end if (self.numSel < 2) then mouseEvent.view:DrawMe() return end end mesh:PrepMovePoints() if (self:UseFixedHandles(moho)) then mesh:PrepFixedHandles() end mouseEvent.view:DrawMe() end function LK_TransformPoints:OnMouseMoved(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (not self.dragging) then self.centerVec = mesh:SelectedCenter() local mode = self:TestMousePoint(moho, mouseEvent) if (mode == 0) then mouseEvent.view:SetCursor(MOHO.moveCursor) elseif (mode == 1) then mouseEvent.view:SetCursor(MOHO.rotateCursor) elseif (mode == 11) then mouseEvent.view:SetCursor(MOHO.crosshairCursor) else mouseEvent.view:SetCursor(MOHO.scaleCursor) end mouseEvent.view:DrawMe() return end if (self.mode == self.selectMode) then mouseEvent.ctrlKey = false LM_SelectPoints:OnMouseMoved(moho, mouseEvent) elseif (self.mode == 0) then -- translate self:OnMouseMoved_T(moho, mouseEvent) elseif (self.mode == 1) then -- rotate self:OnMouseMoved_R(moho, mouseEvent) elseif (self.mode == 10) then -- bezier handle LM_Curvature:OnMouseMoved(moho, mouseEvent) return elseif (self.mode == 11) then -- pivot self:OnMouseMoved_P(moho, mouseEvent) else -- scale self:OnMouseMoved_S(moho, mouseEvent) end end function LK_TransformPoints:OnMouseMoved_T(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (mouseEvent.ctrlKey) then -- hold down the control key to just select a single point and not move it return end self.endWeldVec:Set(-10000000, -10000000) local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec if (mouseEvent.shiftKey) then if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then curVec.y = 0 else curVec.x = 0 end end if (self.numSel < 2) then -- just working with 1 point if (self.selID == -1) then return end local pt = mesh:Point(self.selID) pt.fPos:Set(pt.fTempPos + curVec) if (moho.gridOn) then moho:SnapToGrid(pt.fPos) end if (not(mouseEvent.altKey) and self.autoWeld and pt:IsEndpoint()) then -- Display the upcoming weld point for the user's benefit local m = LM.Matrix:new_local() local testVec1 = LM.Vector2:new_local() local p1 = LM.Point:new_local() local testVec2 = LM.Vector2:new_local() local p2 = LM.Point:new_local() local dist = 0 local curveID = -1 local segID = -1 local pickWidth = 3 self.endWeldVec:Set(-10000000, -10000000) testVec1:Set(pt.fPos) moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) m:Transform(testVec1) moho.view:Graphics():WorldToScreen(testVec1, p1) -- first try to find another point to weld this one to local closestID = mesh:ClosestPoint(pt.fPos, self.selID) if (closestID >= 0) then testVec2:Set(mesh:Point(closestID).fPos) m:Transform(testVec2) moho.view:Graphics():WorldToScreen(testVec2, p2) dist = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) if (dist < self.autoWeldRadius * self.autoWeldRadius and (not mesh:ArePointsAdjacent(self.selID, closestID))) then self.endWeldToPoint = true self.endWeldVec:Set(mesh:Point(closestID).fPos) else while (pickWidth < self.autoWeldRadius) do curveID, segID = pt:GetEndpointEdge(curveID, segID) curveID, segID = moho.view:PickEdge(p1, curveID, segID, pickWidth) if (curveID >= 0) then -- add a point in the middle of some curve if ((not mesh:Curve(curveID):IsPointOnSegment(self.selID, segID)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selID, segID - 1)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selID, segID + 1))) then -- don't weld the point back on itself self.endWeldToPoint = false self.endWeldVec:Set(mesh:Curve(curveID):ClosestPointOnSegment(segID, pt.fPos, true, true)) break end end pickWidth = pickWidth + 3 end -- while end end end else -- move multiple points if (moho.gridOn) then if (self.selID > -1) then local pt = mesh:Point(self.selID) local tempVec = pt.fTempPos + curVec moho:SnapToGrid(tempVec) curVec:Set(tempVec - pt.fTempPos) else moho:SnapToGrid(curVec) end end mesh:TranslatePoints(curVec) end moho:AddPointKeyframe(moho.drawingFrame) if (self:UseFixedHandles(moho)) then mesh:PreserveHandlePositions() end mouseEvent.view:DrawMe() end function LK_TransformPoints:OnMouseMoved_S(moho, mouseEvent) if (self.numSel < 2) then return end local mesh = moho:DrawingMesh() if (mesh == nil) then return end local center = LM.Vector2:new_local() center:Set(self.centerVec) if (mouseEvent.altKey) then center:Set(self.centerVec) else if (self.mode == 6) then -- LEFT center:Set(self.selectedMax.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) elseif (self.mode == 7) then -- RIGHT center:Set(self.selectedMin.x, (self.selectedMin.y + self.selectedMax.y) / 2.0) elseif (self.mode == 8) then -- TOP center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMin.y) elseif (self.mode == 9) then -- BOTTOM center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMax.y) elseif (self.mode == 4) then -- BL center:Set(self.selectedMax.x, self.selectedMax.y) elseif (self.mode == 2) then -- TL center:Set(self.selectedMax.x, self.selectedMin.y) elseif (self.mode == 3) then -- TR center:Set(self.selectedMin.x, self.selectedMin.y) elseif (self.mode == 5) then -- BR center:Set(self.selectedMin.x, self.selectedMax.y) end end local scaling = LM.Vector2:new_local() scaling:Set(1, 1) -- scaling connected to actual drag amount local v1 = mouseEvent.drawingStartVec - center local v2 = mouseEvent.drawingVec - center scaling.x = v2.x / v1.x scaling.y = v2.y / v1.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) then if (scaling.y * self.lastScaleY > 0.0001) then flip = true end elseif (scaling.y * self.lastScaleY < -0.0001) then if (scaling.x * self.lastScaleX > 0.0001) then flip = true end end mesh:ScalePoints(scaling.x, scaling.y, center, flip) if (mouseEvent.altKey) then local v = mesh:SelectedCenter() self.pivotOffset = self.centerVec - v else local v = self.centerVec - center v.x = v.x * scaling.x v.y = v.y * scaling.y v = v + center self.pivotOffset = v - mesh:SelectedCenter() end if (flip) then self.lastScaleX = scaling.x self.lastScaleY = scaling.y end moho:AddPointKeyframe(moho.drawingFrame) if (self:UseFixedHandles(moho)) then mesh:PreserveHandlePositions() end mouseEvent.view:DrawMe() end function LK_TransformPoints:OnMouseMoved_R(moho, mouseEvent) if (self.numSel < 2) then return end local mesh = moho:DrawingMesh() if (mesh == nil) then return end local angle = self.startAngle local v1 = self.lastVec - self.centerVec local v2 = mouseEvent.drawingVec - self.centerVec 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 / 4) angle = (math.pi / 4) * LM.Round(angle) end mesh:RotatePoints(angle, self.centerVec) moho:AddPointKeyframe(moho.drawingFrame) self.lastVec:Set(mouseEvent.drawingVec) if (self:UseFixedHandles(moho)) then mesh:PreserveHandlePositions() end mouseEvent.view:DrawMe() end function LK_TransformPoints:OnMouseMoved_P(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec if (mouseEvent.shiftKey) then if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then curVec.y = 0 else curVec.x = 0 end end self.pivotOffset = self.startPivotOffset + curVec self.centerVec = mesh:SelectedCenter() self.centerVec = self.centerVec + self.pivotOffset mouseEvent.view:DrawMe() end function LK_TransformPoints:OnMouseUp(moho, mouseEvent) if (self.mode == self.selectMode) then mouseEvent.ctrlKey = false LM_SelectPoints:OnMouseUp(moho, mouseEvent) self.dragging = false self.selID = -1 mouseEvent.view:DrawMe() return end local mesh = moho:DrawingMesh() if (mesh == nil) then return end -- if we're just moving a single point, then try to auto-weld it if (self.mode == 0 and self.selID >= 0 and self.numSel == 1 and self.autoWeld and not(mouseEvent.altKey) and moho.drawingLayer:CurrentAction() == "" and not(moho:DisableDrawingTools())) then if (mesh:Point(self.selID):IsEndpoint()) then if (not LK_TransformPoints:WeldPoints(moho, mouseEvent.view, self.dragging) and self.selID >= 0) then -- Failed to weld this endpoint to another point. -- Instead, try welding it to the middle of a nearby curve. local m = LM.Matrix:new_local() local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local curveID = -1 local segID = -1 local pickWidth = 3 moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) v:Set(mesh:Point(self.selID).fPos) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) while (pickWidth < self.autoWeldRadius) do curveID, segID = mesh:Point(self.selID):GetEndpointEdge(curveID, segID) curveID, segID = moho.view:PickEdge(pt, curveID, segID, pickWidth) if (curveID >= 0) then -- add a point in the middle of some curve if ((not mesh:Curve(curveID):IsPointOnSegment(self.selID, segID)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selID, segID - 1)) and (not mesh:Curve(curveID):IsPointOnSegment(self.selID, segID + 1))) then -- don't weld the point back on itself local curve = mesh:Curve(curveID) mesh:AddPoint(curve:ClosestPointOnSegment(segID, mesh:Point(self.selID).fPos, true, true), curveID, segID, moho.drawingLayerFrame) if (mesh:WeldPoints(self.selID, mesh:CountPoints() - 1, moho.drawingLayerFrame)) then moho:Click() if ((self.autoFill or self.autoStroke) and (not mesh:ContinuousTriangulation())) then self:CreateShape(moho, mesh, mesh:CountPoints() - 1, self.autoFill) end end break end end pickWidth = pickWidth + 3 end end end end self.dragging = false if (self.mode == 10) then -- bezier handle LM_Curvature:OnMouseUp(moho, mouseEvent) elseif (self.mode ~= 11) then moho:AddPointKeyframe(moho.drawingFrame, nil, MOHO.MohoGlobals.EditMultipleKeys) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() if (self.mode == 0) then -- translate : don't modify the pivot elseif (self.mode == 1) then -- rotate : move the pivot local v = mesh:SelectedCenter() self.pivotOffset = self.centerVec - v end end self.selID = -1 if (mouseEvent.pt.x == mouseEvent.startPt.x and mouseEvent.pt.y == mouseEvent.startPt.y) then --#34389 - allow shift key to pass to select points so extended selections are possible --mouseEvent.shiftKey = false mouseEvent.ctrlKey = false mouseEvent.altKey = false LM_SelectPoints:SingleClickSelect(moho, mouseEvent, false, true) end end function LK_TransformPoints:OnKeyDown(moho, keyEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (keyEvent.keyCode == LM.GUI.KEY_BIND) then local doit = false if (self.dragging) then if (self.numSel == 1) then doit = true end else if (moho:CountSelectedPoints() == 1) then doit = true end end if (doit) then -- try welding the selected point to the nearest other point if (not LK_TransformPoints:WeldPoints(moho, keyEvent.view, self.dragging)) then -- Failed to weld this endpoint to another point. -- Instead, try welding it to the middle of a nearby curve. local selID = -1 for i = 0, mesh:CountPoints() - 1 do if (mesh:Point(i).fSelected) then selID = i break end end if (selID >= 0) then local m = LM.Matrix:new_local() local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local curveID = -1 local segID = -1 local pickWidth = 3 moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) v:Set(mesh:Point(selID).fPos) m:Transform(v) keyEvent.view:Graphics():WorldToScreen(v, pt) while (pickWidth < self.autoWeldRadius) do curveID, segID = mesh:Point(selID):GetEndpointEdge(curveID, segID) curveID, segID = moho.view:PickEdge(pt, curveID, segID, pickWidth) if (curveID >= 0) then -- add a point in the middle of some curve if ((not mesh:Curve(curveID):IsPointOnSegment(selID, segID))) then -- don't weld the point back on itself local curve = mesh:Curve(curveID) mesh:AddPoint(curve:ClosestPointOnSegment(segID, mesh:Point(selID).fPos, true, true), curveID, segID, moho.drawingLayerFrame) if (mesh:WeldPoints(selID, mesh:CountPoints() - 1, moho.drawingLayerFrame)) then moho:Click() if ((self.autoFill or self.autoStroke) and (not mesh:ContinuousTriangulation())) then self:CreateShape(moho, mesh, mesh:CountPoints() - 1, self.autoFill) end end break end end pickWidth = pickWidth + 3 end end else self.selID = -1 self.numSel = -1 --mesh:SelectNone() end keyEvent.view:DrawMe() 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.drawingLayer) moho.document:SetDirty() MOHO.DeleteSelectedPoints(mesh) keyEvent.view:DrawMe() end elseif (keyEvent.ctrlKey) then local inc = 1 if (keyEvent.shiftKey) then inc = 10 end local m = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) local fakeME = {} fakeME.view = keyEvent.view fakeME.pt = LM.Point:new_local() fakeME.pt:Set(keyEvent.view:Graphics():Width() / 2, keyEvent.view:Graphics():Height() / 2) fakeME.startPt = LM.Point:new_local() fakeME.startPt:Set(fakeME.pt) fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.drawingVec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.drawingStartVec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.shiftKey = false fakeME.ctrlKey = false fakeME.altKey = keyEvent.altKey fakeME.penPressure = 0 fakeME.doubleClick = false fakeME.eraser = false self.keyMovement = true if (keyEvent.keyCode == LM.GUI.KEY_UP) then moho.document:PrepUndo(MOHO.Localize("/Scripts/Tool/TransformPoints/TransformPointsUndoAction=Transform Point"), moho.drawingLayer) self.selID = self:SelIDForNudge(moho, mesh) if (self.selID == -2) then self.selID = -1 return end self:OnMouseDown(moho, fakeME) fakeME.pt.y = fakeME.pt.y - inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.drawingVec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_DOWN) then moho.document:PrepUndo(MOHO.Localize("/Scripts/Tool/TransformPoints/TransformPointsUndoAction=Transform Point"), moho.drawingLayer) self.selID = self:SelIDForNudge(moho, mesh) if (self.selID == -2) then self.selID = -1 return end self:OnMouseDown(moho, fakeME) fakeME.pt.y = fakeME.pt.y + inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.drawingVec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_LEFT) then moho.document:PrepUndo(MOHO.Localize("/Scripts/Tool/TransformPoints/TransformPointsUndoAction=Transform Point"), moho.drawingLayer) self.selID = self:SelIDForNudge(moho, mesh) if (self.selID == -2) then self.selID = -1 return end self:OnMouseDown(moho, fakeME) fakeME.pt.x = fakeME.pt.x - inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.drawingVec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_RIGHT) then moho.document:PrepUndo(MOHO.Localize("/Scripts/Tool/TransformPoints/TransformPointsUndoAction=Transform Point"), moho.drawingLayer) self.selID = self:SelIDForNudge(moho, mesh) if (self.selID == -2) then self.selID = -1 return end self:OnMouseDown(moho, fakeME) fakeME.pt.x = fakeME.pt.x + inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.drawingVec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) end self.keyMovement = false end moho:UpdateUI() end function LK_TransformPoints:OnInputDeviceEvent(moho, deviceEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return false end if (moho:CountSelectedPoints() < 1) then return false end 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(moho.drawingLayer) self.numSel = moho:CountSelectedPoints() mesh:PrepMovePoints() if (self:UseFixedHandles(moho)) then mesh:PrepFixedHandles() end self.centerVec = mesh:SelectedCenter() 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 LK_TransformPoints:DrawMe(moho, view) if (moho:IsPlaying()) then return end local g = view:Graphics() local layerMatrix = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, layerMatrix, moho.document) g:Push() g:ApplyMatrix(layerMatrix) if (self.lastSelectedCount ~= moho:CountSelectedPoints()) then self.lastSelectedCount = moho:CountSelectedPoints() self.pivotOffset:Set(0, 0) end if (self.mode == self.selectMode and self.dragging) then LM_SelectPoints:DrawMe(moho, view) elseif (self.fillingShape) then local matrix = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.frame, matrix, moho.document) 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 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) elseif (not self.dragging or self.mode == 11) then local mesh = moho:DrawingMesh() if (mesh == nil) then return end self.numSel = moho:CountSelectedPoints() if (self.numSel >= 2) then local g = view:Graphics() local min = LM.Vector2:new_local() local max = LM.Vector2:new_local() local matrix = LM.Matrix: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:SelectedMeshBounds(moho, moho.drawingLayer, mesh, moho.drawingFrame, view) min:Set(bbox.fMin.x, bbox.fMin.y) max:Set(bbox.fMax.x, bbox.fMax.y) g:SetColor(col) g:SetPenWidth(1) 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: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) 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) if (self.dragging) then centerVec:Set(self.centerVec) else centerVec = mesh:SelectedCenter() 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) end end -- * Lukas mod draw bezier handles: if self.showHandles then local mesh = moho:DrawingMesh() if mesh == nil then return end local g = view:Graphics() g:SetSmoothing(true) local meshLayer = moho:LayerAsVector(moho.drawingLayer) local selectedOnly = false -- * Currently always false -- * Curves: for i=0, mesh:CountCurves()-1 do local curve = mesh:Curve(i) local vec2 = LM.Vector2:new_local() vec2:Set(0,0) -- * Point Handles: for i = 0, curve:CountPoints()-1 do local point = curve:Point(i) local firstPoint = false local lastPoint = false if i == 0 and point:IsEndpoint() then firstPoint = true elseif point:IsEndpoint() then lastPoint = true end -- if not point.fHidden and (not selectedOnly or point.fSelected) then local ptPos = point.fPos local handlePos = curve:GetControlHandle(i, moho.frame, true) local handlePos2 = curve:GetControlHandle(i, moho.frame, false) -- * Lines to handles: g:SetColor(63, 77, 76) -- * Handle color preference is not available, there's no MOHO.MohoGlobals.HandleCol if not firstPoint then g:DrawLine(ptPos.x, ptPos.y, handlePos.x, handlePos.y) end if not lastPoint then g:DrawLine(ptPos.x, ptPos.y, handlePos2.x, handlePos2.y) end -- * Handles: local handleRadius = 3 if point.fSelected then g:SetColor(MOHO.MohoGlobals.SelCol) end if not firstPoint then g:FillCirclePixelRadius(handlePos, handleRadius) end if not lastPoint then g:FillCirclePixelRadius(handlePos2, handleRadius) end if not point.fSelected or self.lockedMode then g:SetColor(MOHO.MohoGlobals.ElemCol) end if point.fSelected and not self.lockedMode then g:SetColor(MOHO.MohoGlobals.SelCol) end g:DrawFatMarker(ptPos.x, ptPos.y, 3) -- * Default point. end end -- * end end -- * end bezier mod -- * start Lukas mod color points: local mesh = moho:DrawingMesh() if MOHO.hasbit(view:QualityFlags(), MOHO.bit(MOHO.LDQ_WIREFRAME)) then if mesh ~= nil then for i = 0, mesh:CountGroups()-1 do local group = mesh:Group(i) for j = 0, group:CountPoints()-1 do local groupName = group:Name() if groupName ~= "Shy" then local color = 12 for c = 1, #FO_Utilities.colorNames do local colorName = FO_Utilities.colorNames[c] if string.lower(groupName) == string.lower(colorName) then color = c end end local point = group:Point(j) if not point.fHidden then if point.fSelected then g:SetColor(MOHO.MohoGlobals.SelCol) g:DrawFatMarker(point.fPos.x, point.fPos.y, 4) else g:SetColor(MOHO.MohoGlobals.ElemCol) g:DrawFatMarker(point.fPos.x, point.fPos.y, 3) end g:SetColor(FO_Utilities.colorsR[color], FO_Utilities.colorsG[color], FO_Utilities.colorsB[color]) g:DrawFatMarker(point.fPos.x, point.fPos.y, 2) end end end end end end -- * end Lukas mod color points g:Pop() end function LK_TransformPoints:WeldPoints(moho, view, dragging) local mesh = moho:DrawingMesh() if (mesh == nil) then return false end 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(moho.drawingLayer) 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 LK_TransformPoints: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 mesh:SelectNone() mesh:Point(ptID).fSelected = true end return shapeID end function LK_TransformPoints:SelIDForNudge(moho, mesh) local id = moho:CountSelectedPoints() if (id < 1) then return -2 elseif (id > 1) then return -1 else for i = 0, mesh:CountPoints() - 1 do if (mesh:Point(i).fSelected) then return i end end end end function LK_TransformPoints: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 -- ************************************************** LK_TransformPoints.DUMMY = MOHO.MSG_BASE LK_TransformPoints.CHANGE = MOHO.MSG_BASE + 1 LK_TransformPoints.MODIFY_S = MOHO.MSG_BASE + 2 LK_TransformPoints.MODIFY_R = MOHO.MSG_BASE + 3 LK_TransformPoints.RESET = MOHO.MSG_BASE + 4 LK_TransformPoints.AUTOWELD = MOHO.MSG_BASE + 5 LK_TransformPoints.AUTOFILL = MOHO.MSG_BASE + 6 LK_TransformPoints.AUTOSTROKE = MOHO.MSG_BASE + 7 LK_TransformPoints.SHOWHANDLES = MOHO.MSG_BASE + 8 LK_TransformPoints.FIXEDHANDLES = MOHO.MSG_BASE + 9 LK_TransformPoints.FLIP_H = MOHO.MSG_BASE + 10 LK_TransformPoints.FLIP_V = MOHO.MSG_BASE + 11 LK_TransformPoints.SELECTITEM = MOHO.MSG_BASE + 12 LK_TransformPoints.autoWeld = false LK_TransformPoints.autoWeldRadius = 12 LK_TransformPoints.autoFill = false LK_TransformPoints.autoStroke = false LK_TransformPoints.showHandles = false LK_TransformPoints.fixedHandles = true function LK_TransformPoints:DoLayout(moho, layout) 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) 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) end function LK_TransformPoints:UpdateWidgets(moho) if (moho:CurrentTool() ~= "LK_TransformPoints") then return -- this could get called when doing a double-tap on a multitouch Wacom device with a different active tool end local mesh = moho:DrawingMesh() if (mesh == nil) then return end MOHO.BuildGroupMenu(self.menu, mesh, self.SELECTITEM, self.DUMMY) local center = mesh:SelectedCenter() self.textX:SetValue(center.x) self.textY:SetValue(center.y) self.scaleX:SetValue(1) self.scaleY:SetValue(1) self.angle:SetValue(0) self.autoWeldCheck:SetValue(self.autoWeld) self.autoWeldCheck:Enable(not mesh:ContinuousTriangulation()) self.autoFillCheck:SetValue(self.autoFill) self.autoStrokeCheck:SetValue(self.autoStroke) 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) if (moho:CountSelectedPoints() > 1) then self.flipH:Enable(true) self.flipV:Enable(true) else self.flipH:Enable(false) self.flipV:Enable(false) end end function LK_TransformPoints:HandleMessage(moho, view, msg) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (msg == self.CHANGE) then moho.document:PrepUndo(moho.drawingLayer) moho.document:SetDirty() local offset = mesh:SelectedCenter() offset.x = self.textX:FloatValue() - offset.x offset.y = self.textY:FloatValue() - offset.y mesh:PrepMovePoints() if (self:UseFixedHandles(moho)) then mesh:PrepFixedHandles() end mesh:TranslatePoints(offset) moho:AddPointKeyframe(moho.drawingFrame, nil, MOHO.MohoGlobals.EditMultipleKeys) if (self:UseFixedHandles(moho)) then mesh:PreserveHandlePositions() end moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.RESET) then if (moho.drawingFrame > 0) then moho.document:PrepUndo(moho.drawingLayer) 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.drawingLayerFrame) end end end self:UpdateWidgets(moho) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.MODIFY_S) then moho.document:PrepUndo(moho.drawingLayer) moho.document:SetDirty() local centerVec = mesh:SelectedCenter() centerVec = centerVec + self.pivotOffset local scaleX = self.scaleX:FloatValue() local scaleY = self.scaleY:FloatValue() self.scaleX:SetValue(1) self.scaleY:SetValue(1) mesh:PrepMovePoints() if (self:UseFixedHandles(moho)) then mesh:PrepFixedHandles() end local flip = false if (scaleX < 0.001) then if (scaleY > 0.001) then flip = true end elseif (scaleY < 0.001) then if (scaleX > 0.001) then flip = true end end mesh:ScalePoints(scaleX, scaleY, centerVec, flip) local v = mesh:SelectedCenter() self.pivotOffset = centerVec - v moho:AddPointKeyframe(moho.drawingFrame, nil, MOHO.MohoGlobals.EditMultipleKeys) if (self:UseFixedHandles(moho)) then mesh:PreserveHandlePositions() end moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.MODIFY_R) then moho.document:PrepUndo(moho.drawingLayer) moho.document:SetDirty() local centerVec = mesh:SelectedCenter() centerVec = centerVec + self.pivotOffset local angle = math.rad(self.angle:FloatValue()) self.angle:SetValue(0) mesh:PrepMovePoints() if (self:UseFixedHandles(moho)) then mesh:PrepFixedHandles() end mesh:RotatePoints(angle, centerVec) local v = mesh:SelectedCenter() self.pivotOffset = centerVec - v moho:AddPointKeyframe(moho.drawingFrame, nil, MOHO.MohoGlobals.EditMultipleKeys) if (self:UseFixedHandles(moho)) then mesh:PreserveHandlePositions() end moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.AUTOWELD) then self.autoWeld = self.autoWeldCheck:Value() elseif (msg == self.AUTOFILL) then self.autoFill = self.autoFillCheck:Value() elseif (msg == self.AUTOSTROKE) then self.autoStroke = self.autoStrokeCheck:Value() elseif (msg == self.SHOWHANDLES) then if (MOHO.IsMohoPro()) then self.showHandles = self.showHandleCheck:Value() moho:UpdateUI() end elseif (msg == self.FIXEDHANDLES) then if (MOHO.IsMohoPro()) then self.fixedHandles = self.fixedHandleCheck:Value() end elseif (msg == self.FLIP_H) then moho.document:PrepUndo(moho.drawingLayer) moho.document:SetDirty() local center = mesh:SelectedCenter() for i = 0, mesh:CountPoints() - 1 do local pt = mesh:Point(i) if (pt.fSelected) then local f = center.x - pt.fPos.x pt.fPos.x = center.x + f pt:FlipControlHandles(moho.drawingFrame) end end moho:AddPointKeyframe(moho.drawingFrame) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() elseif (msg == self.FLIP_V) then moho.document:PrepUndo(moho.drawingLayer) moho.document:SetDirty() local center = mesh:SelectedCenter() for i = 0, mesh:CountPoints() - 1 do local pt = mesh:Point(i) if (pt.fSelected) then local f = center.y - pt.fPos.y pt.fPos.y = center.y + f pt:FlipControlHandles(moho.drawingFrame) end end moho:AddPointKeyframe(moho.drawingFrame) moho:NewKeyframe(CHANNEL_POINT) moho:UpdateUI() 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
Transform Points
Unlisted
Author: Lukas
View Script
Script type: Tool
Uploaded: Jun 02 2022, 13:54
Last modified: Jun 07 2022, 03:07
Transform Points mod with custom bezier looks and color points
If you're using LK_SelectPoints and LK_Curvature, you probably also want the transform tool to look the same. This is the standard tool, with only some viewport tweaks.
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: 230
Transform Points
Unlisted
Author: Lukas
View Script
Script type: Tool
Uploaded: Jun 02 2022, 13:54
Last modified: Jun 07 2022, 03:07
Transform Points mod with custom bezier looks and color points
If you're using LK_SelectPoints and LK_Curvature, you probably also want the transform tool to look the same. This is the standard tool, with only some viewport tweaks.
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: 230