-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "AE_HandsTable" -- ************************************************** -- General information about this script -- ************************************************** AE_HandsTable = {} function AE_HandsTable:Name() return 'Hands table' end function AE_HandsTable:Version() return '1.3' end function AE_HandsTable:UILabel() return 'Hands table' end function AE_HandsTable:Creator() return 'Alexandra Evseeva' end function AE_HandsTable:Description() return 'Click to select a switch, alt-click to select another switch. Select switch child to setup the table' end function AE_HandsTable:ColorizeIcon() return true end function AE_HandsTable:LoadPrefs(prefs) self.radius = prefs:GetFloat("AE_HandsTable.radius", 0.1) self.startX = prefs:GetFloat("AE_HandsTable.startX", 0) self.startY = prefs:GetFloat("AE_HandsTable.startY", 0) end function AE_HandsTable:SavePrefs(prefs) prefs:SetFloat("AE_HandsTable.radius",self.radius) prefs:SetFloat("AE_HandsTable.startX",self.startX) prefs:SetFloat("AE_HandsTable.startY",self.startY) end function AE_HandsTable:ResetPrefs(prefs) self.radius = 0.1 self.startX = 0 self.startY = 0 end AE_HandsTable.radius = 0.1 AE_HandsTable.startX = 0 AE_HandsTable.startY = 0 AE_HandsTable.defaultStartX = 0 AE_HandsTable.defaultStartY = 1 AE_HandsTable.defaultRadius = 0.1 AE_HandsTable.over = false AE_HandsTable.fixed = {0,0,0,0} AE_HandsTable.layerDataPrefix = 'AE_HandsTable' AE_HandsTable.lastLayer = nil --AE_HandsTable.nameTableLength = 0 AE_HandsTable.flipIcons = false AE_HandsTable.flipVIcons = false AE_HandsTable.previousName = nil -- ************************************************** -- Is Relevant / Is Enabled -- ************************************************** function AE_HandsTable:IsRelevant(moho) return true end function AE_HandsTable:IsEnabled(moho) --self:UpdateNameTable(moho) return true end -- ************************************************** -- Table interface -- ************************************************** AE_HandsTable.CELL = 10 AE_HandsTable.HLEGEND = 2 AE_HandsTable.VLEGEND = 3 AE_HandsTable.LEGEND = 4 AE_HandsTable.SKIP = 5 AE_HandsTable.CONTENT_CELL = 11 AE_HandsTable.CURRENT = 6 function AE_HandsTable:IterateTable(startX, startY, radius) startX = startX or self.startX or 0 startY = startY or self.startY or 0 radius = radius or self.radius or 0.1 if radius <= 0 then radius = 0.1 end local fixedStartX = startX + 10 * radius local i, j = 0,-1 local fx = 0 local cr = 0 local n = 8 local iterateFn = function() j = j + 1 if j > n then j = 0 i = i + 1 end if i > n then fx = fx + 1 if fx <= (#self.fixed - 1) then return fx, 0, fixedStartX, startY-fx*2*radius, self.LEGEND end cr = cr + 1 if cr > (#self.fixed - 1) then return nil end return cr, 0, startX + cr*radius*2, startY - (n+1)*radius, self.CURRENT end local lx = startX + i*radius local ly = startY - j*radius local cellType = self.CELL if i == 0 and j == 0 then cellType = self.SKIP elseif j == 0 then cellType = self.HLEGEND elseif i == 0 then cellType = self.VLEGEND end return i, j, lx, ly, cellType end return iterateFn end function AE_HandsTable:GetTwoLegends() local legends = {1,2,3,4} for fx = 1, 3 do if self.fixed[fx] > 0 then for i, val in pairs(legends) do if val == fx then table.remove(legends, i) break end end if #legends == 2 then return legends end end end return {legends[1], legends[2]} end function AE_HandsTable:GetElementSignature(i, j) i = i or self.i j = j or self.j local result = {} local legends = self:GetTwoLegends() for dim, fixed in pairs(self.fixed) do if fixed > 0 then table.insert(result, fixed) else if legends[1] == dim then table.insert(result, i) elseif legends[2] == dim then table.insert(result, j) else table.insert(result, 0) end end end return result end function AE_HandsTable:FixValue(fix, value) if fix > #self.fixed then return false end if value == 0 then self.fixed[fix] = 0 return true end local numFixed = 0 for i, val in pairs(self.fixed) do if val > 0 then numFixed = numFixed + 1 end end if numFixed >= (#self.fixed - 2) then return false end self.fixed[fix] = value return true end function AE_HandsTable:TestMouse(moho, mouseEvent) local vec = LM.Vector2:new_local() vec:Set(mouseEvent.vec) local matrix = LM.Matrix:new_local() moho.drawingLayer:GetFullTransform(moho.frame, matrix, moho.document) matrix:Transform(vec) local v = LM.Vector2:new_local() local picked = false local dist = self.radius/3 local legendDist = self.radius for i, j, lx, ly, cellType in self:IterateTable() do if cellType ~= self.SKIP then v:Set(lx,ly) local m = (vec - v):Mag() if cellType == self.LEGEND then if m < legendDist then return true, i, j, cellType end elseif m < dist then return true, i, j, cellType end end end return false end -- ************************************************** -- Keyboard/Mouse Control -- ************************************************** function AE_HandsTable:NonDragMouseMove() return true end function AE_HandsTable:OnMouseMoved(moho, mouseEvent) local over, i, j, cellType = self:TestMouse(moho, mouseEvent) local changed = (self.over ~= over) self.over = over if not changed then if not over then return end if cellType == self.LEGEND then return end if cellType == self.CURRENT then return end if self.i == i and self.j == j then return end end if cellType ~= self.LEGEND and cellType ~= self.CURRENT then self.i = i self.j = j end if cellType == self.CELL then self:EvalSwitch(moho, false) end mouseEvent.view:DrawMe() end function AE_HandsTable:PickSwitch(moho, mouseEvent) local layer = mouseEvent.view:PickGlobalLayer(mouseEvent.pt) local switch = moho:LayerAsSwitch(layer) or layer:AncestorSwitchLayer() if not switch then --TODO: examine all the other layers by select and mouseEvent.view:PickShape(mouseEvent.pt) or something else for bitmaps end while switch:AncestorSwitchLayer() and not (AE_Utilities:IsAncestor(switch:AncestorSwitchLayer(), moho.layer) or switch:AncestorSwitchLayer() == moho.layer) do switch = switch:AncestorSwitchLayer() end if switch then moho:SetSelLayer(switch) moho:ShowLayerInLayersPalette(switch) return true end return false end function AE_HandsTable:OnMouseDown(moho, mouseEvent) if (not moho:LayerAsSwitch(moho.layer) and not moho.layer:AncestorSwitchLayer()) or mouseEvent.altKey then local result = self:PickSwitch(moho, mouseEvent) if result then self:UpdateWidgets(moho) end return end local over, i, j, cellType = self:TestMouse(moho, mouseEvent) if not over then return end local legends = self:GetTwoLegends() if cellType == self.CELL then local currentSignature = self:GetElementSignature(i, j) for dim, val in pairs(currentSignature) do if val == 0 then self:FixValue(legends[1], i) self:FixValue(legends[2], j) return end end self:SetupLayer(moho, currentSignature) self:EvalSwitch(moho, true) elseif cellType == self.LEGEND then self:FixValue(i, 0) elseif cellType == self.HLEGEND then self:FixValue(legends[1], i) elseif cellType == self.VLEGEND then self:FixValue(legends[2], j) elseif cellType == self.CURRENT then local currentElementSignature = self:ReadLayerData(moho, moho.layer) if currentElementSignature and currentElementSignature[i] > 0 then self:FixValue(i, currentElementSignature[i]) end end end function AE_HandsTable:OnMouseUp(moho, mouseEvent) end function AE_HandsTable:OnKeyDown(moho, keyEvent) end function AE_HandsTable:OnKeyUp(moho, keyEvent) end function AE_HandsTable:OnInputDeviceEvent(moho, deviceEvent) end function AE_HandsTable:DrawMe(moho, view) if not moho:LayerAsSwitch(moho.layer) and not moho.layer:AncestorSwitchLayer() then return end if not self.icons then self:ReadIcons(moho) end local g = view:Graphics() local v = LM.Vector2:new_local() g:Push() local defaultColor = {255, 0, 0} local R, G, B = table.unpack(defaultColor) g:SetColor(R, G, B, 255) local legends = self:GetTwoLegends() local currentElementSignature = self:ReadLayerData(moho, moho.layer) for i, j, lx, ly, cellType in self:IterateTable() do v:Set(lx,ly) if cellType == self.SKIP then --if self.nameTableLength > 0 then g:FrameCircle(v, self.radius/3) end elseif cellType == self.CELL then local filledCell = self:HasAnything(self:GetElementSignature(i,j)) if filledCell then g:FrameCircle(v, self.radius/3) end if self.over then if self.i == i and self.j == j then g:FillCircle(v, self.radius/3) elseif self.i == i or self.j == j then g:SetColor(R, G, B, 64) g:FillCircle(v, self.radius/3) g:SetColor(R, G, B, 255) end end elseif cellType == self.LEGEND then local fixedValue = self.icons[i] and self.icons[i][self.fixed[i]] if fixedValue then self:DrawIcon(moho, g, lx, ly, self.radius, fixedValue) end elseif cellType == self.CURRENT then if currentElementSignature then local currentIcon = self.icons[i] and self.icons[i][currentElementSignature[i]] if currentIcon then self:DrawIcon(moho, g, lx, ly, self.radius/2, currentIcon) end end else local curArray = nil if cellType == self.HLEGEND then curArray = self.icons[legends[1]] and self.icons[legends[1]][i] end if cellType == self.VLEGEND then curArray = self.icons[legends[2]] and self.icons[legends[2]][j] end if curArray then self:DrawIcon(moho, g, lx, ly, self.radius/2, curArray) end if self.i == i and self.j == j then g:SetColor(R, G, B, 64) g:FillCircle(v, self.radius/3) g:SetColor(R, G, B, 255) end end end g:Pop() end -- ************************************************** -- Tool Panel Layout -- ************************************************** AE_HandsTable.FLIPICONS = MOHO.MSG_BASE + 2 AE_HandsTable.FLIPVICONS = MOHO.MSG_BASE + 4 AE_HandsTable.RESETVIEW = MOHO.MSG_BASE + 3 function AE_HandsTable:DoLayout(moho, layout) self.flipIconsButton = LM.GUI.ImageButton("ScriptResources/flip_points_h", "Flip icons", true, self.FLIPICONS) layout:AddChild(self.flipIconsButton, LM.GUI.ALIGN_LEFT, 0) self.flipVIconsButton = LM.GUI.ImageButton("ScriptResources/flip_points_v", "Flip icons", true, self.FLIPVICONS) layout:AddChild(self.flipVIconsButton, LM.GUI.ALIGN_LEFT, 0) self.resetViewButton = LM.GUI.Button('Reset view', self.RESETVIEW) layout:AddChild(self.resetViewButton, LM.GUI.ALIGN_LEFT, 0) end function AE_HandsTable:HandleMessage(moho, view, msg) if msg == self.BUTTON_1 then self:WriteIcon(moho) elseif msg == self.BUTTON_2 then self:ReadIcons(moho) elseif msg == self.FLIPICONS then self.flipIcons = not self.flipIcons elseif msg == self.FLIPVICONS then self.flipVIcons = not self.flipVIcons elseif msg == self.RESETVIEW then local zoom = moho.view:Graphics():ViewZoom() local offset = moho.view:Graphics():ViewOffset() self.startX = self.defaultStartX - offset.x self.startY = self.defaultStartY - offset.y self.radius = self.defaultRadius/zoom end end function AE_HandsTable:UpdateWidgets(moho) self.flipIconsButton:SetValue(self.flipIcons) self.flipVIconsButton:SetValue(self.flipVIcons) self:UpdateNameTable(moho) end function AE_HandsTable:UpdateNameTable(moho) local newLayer = moho.layer:AncestorSwitchLayer() or moho.layer if self.lastLayer ~= newLayer then self.lastLayer = newLayer self:FillNameTable(moho, newLayer) local switchLayer = moho:LayerAsSwitch(newLayer) if switchLayer then self.previousName = switchLayer:GetValue(moho.layerFrame) end end end -- ************************************************** -- Other Methods -- ************************************************** function AE_HandsTable:DrawIcon(moho, g, x, y, size, pointsArray) local p1 = LM.Vector2:new_local() local p2 = LM.Vector2:new_local() for i, val in pairs(pointsArray) do if i > 1 then local p1x = pointsArray[i-1].x * size local p2x = val.x * size local p1y = pointsArray[i-1].y * size local p2y = val.y * size if self.flipIcons then p1x = x - p1x + size/2 p2x = x - p2x + size/2 else p1x = x + p1x - size/2 p2x = x + p2x - size/2 end if self.flipVIcons then p1y = y - p1y + size/2 p2y = y - p2y + size/2 else p1y = y + p1y - size/2 p2y = y + p2y - size/2 end p1:Set(p1x, p1y) p2:Set(p2x, p2y) g:DrawLine(p1.x, p1.y, p2.x, p2.y) end end end function AE_HandsTable:EvalSwitch(moho, fix) local switchLayer = moho:LayerAsSwitch(moho.layer) if not switchLayer then return end local signature = self:GetElementSignature() if not signature then return end local layerName = self:GetNameTable(moho, signature) if not layerName then if self.previousName then switchLayer:SetValue(moho.frame, self.previousName) end return end local childLayer = switchLayer:LayerByName(layerName) if not childLayer then self:FillNameTable(moho, switchLayer) moho:UpdateUI() return end switchLayer:SetValue(moho.frame, layerName) if fix then self.previousName = layerName moho:UpdateUI() end end function AE_HandsTable:SetupLayer(moho, signature) local layer = moho.layer:AncestorSwitchChild() if not layer then return end local oldSignature = self:ReadLayerData(moho, layer) if oldSignature and LM.GUI.Alert(LM.GUI.ALERT_INFO, "This layer is always applied to", table.concat(oldSignature, ' '), "Do you realy want to change it?", "YES", "Cancel") == 1 then return end signature = signature or self:GetElementSignature() local oldLayerName = self:GetNameTable(moho, signature) if oldLayerName and LM.GUI.Alert(LM.GUI.ALERT_INFO, "This place is always occupied by", oldLayerName, "Do you realy want to replace it?", "YES", "Cancel") == 1 then return end self:WriteLayerData(moho, layer, signature, nil, true) self:SetNameTable(moho, signature, layer) if oldSignature then self:FillNameTable(moho, layer:AncestorSwitchLayer()) end end function AE_HandsTable:GetFolder(moho, filename) if filename then filename = filename .. ".dat" else filename = "" end local dir = "/Scripts/ScriptResources/ae_hand_table/" local sVersion = string.gsub(moho:AppVersion(), "^(%d+)(%.%d+)(%..+)", "%1%2") local version = tonumber(sVersion) if version < 13 then dir = string.lower(dir) end return moho:UserAppDir() .. dir .. filename end function AE_HandsTable:WriteIcon(moho) local mesh = moho:Mesh() if not mesh then return end local bounds = moho.layer:Bounds(moho.frame) local maxBound = bounds:MaxDimension2D() local addVect = bounds.fMax - bounds.fMin if addVect.x < addVect.y then addVect:Set((1-addVect.x/maxBound)/2, 0) else addVect:Set(0, (1-addVect.y/maxBound)/2) end local curve = mesh:Curve(0) local pointsArray = {} for p = 0, curve:CountPoints() - 1 do local point = curve:Point(p) table.insert(pointsArray, {x=(point.fPos.x - bounds.fMin.x)/maxBound + addVect.x,y=(point.fPos.y - bounds.fMin.y)/maxBound + addVect.y}) end -- save to file local filePath = self:GetFolder(moho, "0") local file = io.open(filePath, "a+") io.output(file) for i, val in pairs(pointsArray) do io.write(string.char(127 + val.x * 128)..string.char(127 + val.y * 128)) end io.write("\n") io.close() end function AE_HandsTable:ReadIcons(moho) self.icons = {} for dim = 1, #self.fixed do local filePath = self:GetFolder(moho, tostring(dim)) if AE_Utilities:FileExists(filePath) then self.icons[dim] = {} for line in io.lines(filePath) do local nextPointsArray = {} for i = 1, string.len(line)-1, 2 do local lx = string.byte(string.sub(line, i, i+1)) local ly = string.byte(string.sub(line, i+1, i+2)) table.insert(nextPointsArray, {x=(lx-127)/128, y=(ly-127)/128}) end table.insert(self.icons[dim], nextPointsArray) end end end end function AE_HandsTable:EncodeLayerData(dataArray) local encodedString = '' for dim, val in pairs(dataArray) do local sn = 127 + val encodedString = encodedString .. string.char(sn) end return encodedString end function AE_HandsTable:DecodeLayerData(dataString) local dataArray = {} for i = 1, #dataString do local val = string.byte(string.sub(dataString, i, i+1)) table.insert(dataArray, val-127) end return dataArray end function AE_HandsTable:WriteLayerData(moho, layer, dataArray, i, doReplace) local data = layer:ScriptData() dataName = self.layerDataPrefix if i and doReplace then dataName = dataName .. i else --TODO: find a suitable i to add (and also must write an iterator function for reading such values) end local encodedString = self:EncodeLayerData(dataArray) data:Set(dataName, encodedString) end function AE_HandsTable:ReadLayerData(moho, layer, i) if not layer then return nil end local data = layer:ScriptData() local dataName = self.layerDataPrefix if i then dataName = dataName .. i end local stringValue = data:GetString(dataName) if stringValue and #stringValue == #self.fixed then return self:DecodeLayerData(stringValue) end return nil end function AE_HandsTable:SetNameTable(moho, signature, layer) --, dontCount) if not self.nameTable then self.nameTable = {} end local curTable = self.nameTable for i, val in pairs(signature) do if i < #signature then if not curTable[val] then curTable[val] = {} end curTable = curTable[val] else if layer then curTable[val] = layer:Name() else curTable[val] = nil end break end end --if not dontCount then self.nameTableLength = self:NameTableLength() end end function AE_HandsTable:HasAnything(signature, level, t) level = level or 1 if level == 1 then t = self.nameTable end local i1, i2 = 1, 8 if signature[level] > 0 then i1 = signature[level] i2 = signature[level] end for i = i1, i2 do if t[i] then if type(t[i]) == 'table' then result = self:HasAnything(signature, level+1, t[i]) if result then return true end else return true end end end return false end function AE_HandsTable:GetNameTable(moho, signature) if not self.nameTable then return nil end if true then return self.nameTable[signature[1]] and self.nameTable[signature[1]][signature[2]] and self.nameTable[signature[1]][signature[2]][signature[3]] and self.nameTable[signature[1]][signature[2]][signature[3]][signature[4]] end local curTable = self.nameTable for i, val in pairs(signature) do if i < #signature then if not curTable[val] then return nil end curTable = curTable[val] else return curTable[val] end end end function AE_HandsTable:FillNameTable(moho, layer) self.nameTable = {} --self.nameTableLength = 0 local switchLayer = moho:LayerAsSwitch(layer) if not switchLayer then return end for i = 0, switchLayer:CountLayers() - 1 do local nextLayer = switchLayer:Layer(i) local signature = self:ReadLayerData(moho, nextLayer) --TODO: call iterator hear if signature then self:SetNameTable(moho, signature, nextLayer) --, true) --self.nameTableLength = self.nameTableLength + 1 end end end --[[ function AE_HandsTable:NameTableLength(nextTable) nextTable = nextTable or self.nameTable if not nextTable then return 0 end local subCounts = 0 for i,val in pairs(nextTable) do if type(val) ~= "table" then return #nextTable end subCounts = subCounts + self:NameTableLength(val) end return subCounts end --]]
Switch hands organizer
Listed
Author: A.Evseeva
View Script
Script type: Tool
Uploaded: Apr 21 2022, 15:46
Last modified: Jun 28 2022, 11:16
Graphic UI showing 4D table for sorting hand variants used in switch layer
Click to select switch layer, alt-click to select another switch layer.
While switch layer is selected use table to see (mouse move) and apply (mouse click) any of sorted switch children.
Click on upper table levels walks your to the deeper one. Watching and appliing is possible on the last level.
To go level up click on the right icons showing selected levels to deselect it.
Select switch child layer in Moho Layers list View to setup the table (to set a cell for each child)
UPDATES:
v. 1.2: added Vertical Flip button (for display hand icons)
v. 1.3: adapted for Moho 12.x versions (was compartible with 13.5 only)
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: 177

Switch hands organizer
Listed
Author: A.Evseeva
View Script
Script type: Tool
Uploaded: Apr 21 2022, 15:46
Last modified: Jun 28 2022, 11:16
Graphic UI showing 4D table for sorting hand variants used in switch layer
Click to select switch layer, alt-click to select another switch layer.
While switch layer is selected use table to see (mouse move) and apply (mouse click) any of sorted switch children.
Click on upper table levels walks your to the deeper one. Watching and appliing is possible on the last level.
To go level up click on the right icons showing selected levels to deselect it.
Select switch child layer in Moho Layers list View to setup the table (to set a cell for each child)
UPDATES:
v. 1.2: added Vertical Flip button (for display hand icons)
v. 1.3: adapted for Moho 12.x versions (was compartible with 13.5 only)
While switch layer is selected use table to see (mouse move) and apply (mouse click) any of sorted switch children.
Click on upper table levels walks your to the deeper one. Watching and appliing is possible on the last level.
To go level up click on the right icons showing selected levels to deselect it.
Select switch child layer in Moho Layers list View to setup the table (to set a cell for each child)
UPDATES:
v. 1.2: added Vertical Flip button (for display hand icons)
v. 1.3: adapted for Moho 12.x versions (was compartible with 13.5 only)
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: 177