-- **************************************************** -- Provide Moho with the name of this script object -- **************************************************** ScriptName = "SS_Overlayer" -- **************************************************** -- Overlayer - Graphical Text & Timecode overlays -- version: 01.00 MH12+ #540126 (based on SS SMPTE v2) -- by Sam Cogheil (SimplSam) -- **************************************************** --[[ ***** Licence & Warranty ***** Copyright 2024 - Sam Cogheil (SimplSam) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 Conditions require preservation of copyright and license notices. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works. You can: Use - use/reuse freely, even commercially Adapt - remix, transform, and build upon for any purpose Share - redistribute the material in any medium or format Adapt / Share under the following terms: Attribution - You must give appropriate credit, provide a link to the Apache 2.0 license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. Licensed works, modifications and larger works may be distributed under different License terms and without source code. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. The Developer Sam Cogheil / SimplSam will not be liable for any direct, indirect or consequential loss of actual or anticipated - data, revenue, profits, business, trade or goodwill that is suffered as a result of the use of the software provided. ]] --[[ ***** SPECIAL THANKS to: * Stan (and team) @ MOHO Scripting -- https://mohoscripting.com * The friendly faces @ Lost Marble Moho forum -- https://www.lostmarble.com/forum ***** ]] SS_Overlayer = {} local SS_Overlayer_Dialog = {} function SS_Overlayer:Name() return "Overlayer" end function SS_Overlayer:Version() return "1.0 #5401" end function SS_Overlayer:Description() return "Counter and Text Overlays" end function SS_Overlayer:Creator() return "Sam Cogheil (SimplSam)" end function SS_Overlayer:UILabel() return "Counter & Text Overlayer" end function SS_Overlayer:ColorizeIcon() return true end function SS_Overlayer:IsRelevant(moho) if (self._MOHO_Version == -1) then self._MOHO_Version, self._MOHO_minor = moho:AppVersion():match("(%d+%.?%d*)%.?(%d*)") self._MOHO_Version = (self._MOHO_Version or -1) + 0 self._MOHO_minor = (tonumber(self._MOHO_minor) or 0) end return true end function SS_Overlayer:IsEnabled(moho) return (moho.layer:CurrentAction() == "") and (moho.document:CurrentDocAction() == "") end -- ************************************************** -- The guts of this script -- ************************************************** -- Overlayer Display Defaults function SS_Overlayer:ResetPrefs() self.isOSWindows = package.config:sub(1, 1) == "\\" self.systemFont = self.isOSWindows and "Calibri Regular" or "Helvetica Regular" self.postfix = " " self.prefix = " " self.fontname = self.systemFont self.fillcol = LM.rgb_color:new_local() self.fillcol.r = 54 self.fillcol.g = 54 self.fillcol.b = 54 self.fillcol.a = 54 self.linecol = LM.rgb_color:new_local() self.linecol.r = 54 self.linecol.g = 54 self.linecol.b = 54 self.linecol.a = 255 self.linewid = 4 self.fontsize = 100 self.nameoverlay = true self.frameoffset = 0 self.framefactor = 1 -- todo deci rounding digits? self.chkfillcol = true self.chklinecol = true self.label = "" self.timecodemode = 1 self.previewtext = "00:00:01:23" self.rendermenot = false self.burnMode = false self.expression = "" end SS_Overlayer:ResetPrefs() SS_Overlayer._MOHO_Version = -1 SS_Overlayer._MOHO_minor = 0 SS_Overlayer.hasLayerScript = false SS_Overlayer.TCMode_ = MOHO.MSG_BASE + 10 SS_Overlayer.TCModeTIMECODE = SS_Overlayer.TCMode_ + 01 SS_Overlayer.TCModeFRAMES = SS_Overlayer.TCMode_ + 02 SS_Overlayer.TCModeFFRAME35 = SS_Overlayer.TCMode_ + 03 SS_Overlayer.TCModeFFRAME16 = SS_Overlayer.TCMode_ + 04 SS_Overlayer.TCModeMILLISEC = SS_Overlayer.TCMode_ + 05 SS_Overlayer.TCModeEXPRSION = SS_Overlayer.TCMode_ + 06 SS_Overlayer.TCModeMax_ = SS_Overlayer.TCModeEXPRSION SS_Overlayer.TCMaxCount = SS_Overlayer.TCModeMax_ - SS_Overlayer.TCMode_ + 1 SS_Overlayer.timecodeprefx = { "smpte: ", "frame: ", "35mff: ", "16mff: ", "milli: ", "expr: ", "smpte: " } function SS_Overlayer:Run(moho) local layerScript = moho:UserAppDir() .. "/scripts/ScriptResources/ss_overlayer/ss_overlayer_layer.lua" local f = io.open(layerScript, "r") -- rename test ?? if f ~= nil then -- script found f:close() self.removeMe = false self.isNewLayer = false local vecLayer = moho.layer local ScriptInfo = vecLayer:ScriptData() -- If not Vector and Empty (or existing Overlayer layer) if (vecLayer:LayerType() ~= MOHO.LT_VECTOR) or ((moho:LayerAsVector(vecLayer):Mesh():CountPoints() > 0) and not ScriptInfo:HasKey("SS_Overlayer_Layer.is_set")) then vecLayer = moho:CreateNewLayer(MOHO.LT_VECTOR) self.isNewLayer = true ScriptInfo = vecLayer:ScriptData() end vecLayer = moho:LayerAsVector(vecLayer) vecLayer:SetImmuneToCamera(true) vecLayer:ShowConstructionCurves(false) if (self._MOHO_Version > 13.5) or ((self._MOHO_Version == 13.5) and (self._MOHO_minor > 1)) then vecLayer:SetIgnoredByLayerPicker(true) end SS_Overlayer.vecLayer = vecLayer self.hasLayerScript = vecLayer:LayerScript() ~= "" -- Load previous? if (ScriptInfo:HasKey("SS_Overlayer_Layer.is_set")) then -- self.isSet = ScriptInfo:GetBool("SS_Overlayer_Layer.is_set") self.prefix = ScriptInfo:GetString("SS_Overlayer_Layer.prefix") self.postfix = ScriptInfo:GetString("SS_Overlayer_Layer.postfix") self.linewid = ScriptInfo:GetFloat("SS_Overlayer_Layer.linewid") self.fontsize = ScriptInfo:GetInt("SS_Overlayer_Layer.fontsize") self.nameoverlay = ScriptInfo:GetBool("SS_Overlayer_Layer.nameoverlay") self.frameoffset = ScriptInfo:GetInt("SS_Overlayer_Layer.frameoffset") self.framefactor = ScriptInfo:GetFloat("SS_Overlayer_Layer.framefactor") if (self.framefactor == 0) then self.framefactor = 1 end self.chkfillcol = ScriptInfo:GetBool("SS_Overlayer_Layer.chkfillcol") self.chklinecol = ScriptInfo:GetBool("SS_Overlayer_Layer.chklinecol") self.fontname = ScriptInfo:GetString("SS_Overlayer_Layer.fontname") self.linecol = ScriptInfo:GetColor("SS_Overlayer_Layer.linecol") self.fillcol = ScriptInfo:GetColor("SS_Overlayer_Layer.fillcol") self.label = ScriptInfo:GetString("SS_Overlayer_Layer.label") self.expression = ScriptInfo:GetString("SS_Overlayer_Layer.expression") self.timecodemode = ScriptInfo:GetInt("SS_Overlayer_Layer.timecodemode") self.rendermenot = ScriptInfo:GetBool("SS_Overlayer_Layer.rendermenot") end local dlog = SS_Overlayer_Dialog:new(moho) if (dlog:DoModal() == LM.GUI.MSG_OK) then if (not self.removeMe) then ScriptInfo:Set("SS_Overlayer_Layer.is_set", true) ScriptInfo:Set("SS_Overlayer_Layer.prefix", self.prefix) ScriptInfo:Set("SS_Overlayer_Layer.postfix", self.postfix) ScriptInfo:Set("SS_Overlayer_Layer.linewid", self.linewid) ScriptInfo:Set("SS_Overlayer_Layer.fontsize", self.fontsize) ScriptInfo:Set("SS_Overlayer_Layer.nameoverlay", self.nameoverlay) ScriptInfo:Set("SS_Overlayer_Layer.frameoffset", self.frameoffset) ScriptInfo:Set("SS_Overlayer_Layer.framefactor", self.framefactor) ScriptInfo:Set("SS_Overlayer_Layer.chkfillcol", self.chkfillcol) ScriptInfo:Set("SS_Overlayer_Layer.chklinecol", self.chklinecol) ScriptInfo:Set("SS_Overlayer_Layer.fontname", self.fontname) ScriptInfo:Set("SS_Overlayer_Layer.linecol", self.linecol) ScriptInfo:Set("SS_Overlayer_Layer.fillcol", self.fillcol) ScriptInfo:Set("SS_Overlayer_Layer.label", self.label) ScriptInfo:Set("SS_Overlayer_Layer.expression", self.expression:gsub('"', "'")) -- dbl quotes to quotes ScriptInfo:Set("SS_Overlayer_Layer.timecodemode", self.timecodemode) ScriptInfo:Set("SS_Overlayer_Layer.rendermenot", self.rendermenot) ScriptInfo:Set("SS_Overlayer_Layer.is_dirty", true) MOHO.Redraw() vecLayer:SetLayerScript(layerScript) -- embed / re-embed layerscript (reload) else -- remove script vecLayer:Mesh():Clear() -- dont work? local customLabel = (self.label ~= "") and self.label or nil local prefixText = customLabel or self.timecodeprefx[LM.Clamp(self.timecodemode, 1, self.TCMaxCount)] vecLayer:SetName(prefixText .. "- - -") vecLayer:SetLayerScript("") -- script suicide MOHO.Redraw() return end moho.document:SetDirty() else -- Dialog was Cancelled. If New Layer was never used, delete it if (self.isNewLayer) then moho:DeleteLayer(vecLayer) -- layer suicide return end end else print(self:Name(), " [error] Could not find: ", layerScript) end end -- ************************************************** -- Dialog stuff -- ************************************************** SS_Overlayer_Dialog.UPDATE = MOHO.MSG_BASE + 01 SS_Overlayer_Dialog.CHECKS = MOHO.MSG_BASE + 02 SS_Overlayer_Dialog.RESET = MOHO.MSG_BASE + 03 SS_Overlayer_Dialog.REMOVE = MOHO.MSG_BASE + 04 SS_Overlayer_Dialog.FACTOR = MOHO.MSG_BASE + 05 function SS_Overlayer_Dialog:new(moho) local d = LM.GUI.SimpleDialog("SS Overlayer Display Properties", SS_Overlayer_Dialog) local l = d:GetLayout() l:PushH() l:PushV() l:PushH() l:PushV() l:AddChild(LM.GUI.StaticText("Prefix text"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText("Postfix text"), LM.GUI.ALIGN_LEFT) d.chkfillcol = LM.GUI.CheckBox("Fill", d.CHECKS) l:AddChild(d.chkfillcol, LM.GUI.ALIGN_LEFT) d.chklinecol = LM.GUI.CheckBox("Stroke", d.CHECKS) l:AddChild(d.chklinecol, LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText("Font Scale %"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText("Display Mode"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText("Frame offset #"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText("Frame factor #"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText("Expression"), LM.GUI.ALIGN_LEFT) l:Pop() l:PushV() d.prefix = LM.GUI.TextControl(40, " ", d.UPDATE, LM.GUI.FIELD_TEXT) l:AddChild(d.prefix, LM.GUI.ALIGN_LEFT) d.postfix = LM.GUI.TextControl(40, " ", d.UPDATE, LM.GUI.FIELD_TEXT) l:AddChild(d.postfix, LM.GUI.ALIGN_LEFT) d.fillcol = LM.GUI.ShortColorSwatch(true, 0) l:AddChild(d.fillcol, LM.GUI.ALIGN_LEFT) l:PushH() d.linecol = LM.GUI.ShortColorSwatch(true, 0) l:AddChild(d.linecol, LM.GUI.ALIGN_LEFT) d.linewid = LM.GUI.TextControl(40, "4", 0, LM.GUI.FIELD_UFLOAT) l:AddChild(d.linewid, LM.GUI.ALIGN_LEFT) l:Pop() d.fontsize = LM.GUI.TextControl(40, "100", 0, LM.GUI.FIELD_UINT) l:AddChild(d.fontsize, LM.GUI.ALIGN_LEFT) d.timecodemodeMenu = LM.GUI.Menu("Display Mode") d.timecodemodePopup = LM.GUI.PopupMenu(120) d.timecodemodePopup:SetMenu(d.timecodemodeMenu) l:AddChild(d.timecodemodePopup, LM.GUI.ALIGN_LEFT) d.timecodemodeMenu:AddItem("Timecode", 0, SS_Overlayer.TCModeTIMECODE) d.timecodemodeMenu:AddItem("Frames", 0, SS_Overlayer.TCModeFRAMES) d.timecodemodeMenu:AddItem("35mm FFrames", 0, SS_Overlayer.TCModeFFRAME35) d.timecodemodeMenu:AddItem("16mm FFrames", 0, SS_Overlayer.TCModeFFRAME16) d.timecodemodeMenu:AddItem("Milliseconds", 0, SS_Overlayer.TCModeMILLISEC) d.timecodemodeMenu:AddItem("Expression", 0, SS_Overlayer.TCModeEXPRSION) d.frameoffset = LM.GUI.TextControl(40, "0", self.UPDATE, LM.GUI.FIELD_INT) l:AddChild(d.frameoffset, LM.GUI.ALIGN_LEFT) d.framefactor = LM.GUI.TextControl(40, "1", self.FACTOR, LM.GUI.FIELD_UFLOAT) l:AddChild(d.framefactor, LM.GUI.ALIGN_LEFT) d.expression = LM.GUI.TextControl(120, "", self.UPDATE, LM.GUI.FIELD_TEXT) l:AddChild(d.expression, LM.GUI.ALIGN_LEFT) l:Pop() l:PushV() l:AddChild(LM.GUI.StaticText(" - (Option) Add text before Overlayer text"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - (Option) Add text after Overlayer text"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - Set the Fill Color or Disable it"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - Set the Outline Color and Width"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - Set the Font scaling (100% default)"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - Set the Display mode"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - First frame offset (0 default)"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - Frame multiplier factor (1 default)"), LM.GUI.ALIGN_LEFT) l:AddChild(LM.GUI.StaticText(" - Expression to calculate display value"), LM.GUI.ALIGN_LEFT) l:Pop() l:Pop() l:AddChild(LM.GUI.Divider(false), LM.GUI.ALIGN_FILL) ---- d.renderMeChk = LM.GUI.CheckBox("Render this counter Layer") l:AddChild(d.renderMeChk, LM.GUI.ALIGN_LEFT) l:PushH() l:PushV() d.nameoverlay = LM.GUI.CheckBox("Overlay counter on Layer name") l:AddChild(d.nameoverlay, LM.GUI.ALIGN_LEFT) l:Pop() l:PushV() d.label = LM.GUI.TextControl(80, "", 0, LM.GUI.FIELD_TEXT, "Custom overlay prefix: ") l:AddChild(d.label, LM.GUI.ALIGN_RIGHT) l:Pop() l:Pop() l:AddChild(LM.GUI.Divider(false), LM.GUI.ALIGN_FILL) ---- d.fontPreview = MOHO.FontPreview(64, 64) l:AddChild(d.fontPreview, LM.GUI.ALIGN_FILL) l:Pop() -- V l:AddPadding(16) d.fontList = LM.GUI.TextList(300, 64, d.UPDATE) moho:FillInFontList(d.fontList) l:AddChild(d.fontList, LM.GUI.ALIGN_FILL) l:Pop() -- H l:PushH(LM.GUI.ALIGN_RIGHT) d.removeButt = LM.GUI.Button("Remove", self.REMOVE) if (SS_Overlayer.hasLayerScript) then l:AddChild(d.removeButt, LM.GUI.ALIGN_RIGHT) end d.resetButt = LM.GUI.Button("Reset", self.RESET) l:AddChild(d.resetButt, LM.GUI.ALIGN_RIGHT) l:Pop() return d end function SS_Overlayer_Dialog:UpdateWidgets() self.prefix:SetValue(SS_Overlayer.prefix) self.postfix:SetValue(SS_Overlayer.postfix) self.linewid:SetValue(SS_Overlayer.linewid) self.fontsize:SetValue(SS_Overlayer.fontsize) self.nameoverlay:SetValue(SS_Overlayer.nameoverlay) self.frameoffset:SetValue(SS_Overlayer.frameoffset) self.framefactor:SetValue(SS_Overlayer.framefactor) self.chkfillcol:SetValue(SS_Overlayer.chkfillcol) self.chklinecol:SetValue(SS_Overlayer.chklinecol) self.fillcol:SetValue(SS_Overlayer.fillcol) self.linecol:SetValue(SS_Overlayer.linecol) self.expression:SetValue(SS_Overlayer.expression) self.timecodemodeMenu:SetChecked(SS_Overlayer.timecodemode + SS_Overlayer.TCMode_, true) self.timecodemodePopup:Redraw() -- reqd Mac if (not self.fontList:SetSelItem(SS_Overlayer.fontname)) then self.fontList:SetSelItem(0) end self.label:SetValue(SS_Overlayer.label) self.renderMeChk:SetValue(not SS_Overlayer.rendermenot) self:HandleMessage(self.UPDATE) -- self.expression:Enable(self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeEXPRSION) end function SS_Overlayer_Dialog:OnValidate() local b = true if (not self:Validate(self.linewid, 0.25, 16)) then b = false end if (not self:Validate(self.fontsize, 10, 200)) then b = false end if (not self:Validate(self.frameoffset, -50, 999999)) then b = false end return b end function SS_Overlayer_Dialog:HandleMessage(msg) if (msg == self.UPDATE) then if (self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeTIMECODE) then SS_Overlayer.previewtext = "00:00:01:23" elseif (self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeFRAMES) then SS_Overlayer.previewtext = "000047" elseif (self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeFFRAME35) then SS_Overlayer.previewtext = "002+15" elseif (self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeFFRAME16) then SS_Overlayer.previewtext = "001+07" elseif (self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeMILLISEC) then SS_Overlayer.previewtext = "00:00:01.958" elseif (self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeEXPRSION) then SS_Overlayer.previewtext = "<Expression Result>" end self.fontPreview:SetPreviewText(self.prefix:Value() .. SS_Overlayer.previewtext .. self.postfix:Value()) self.fontPreview:SetFontName(self.fontList:SelItemLabel()) self.fontPreview:Refresh() self.expression:Enable(self.timecodemodeMenu:FirstCheckedMsg() == SS_Overlayer.TCModeEXPRSION) elseif (msg == self.CHECKS) then self.fillcol:Enable(self.chkfillcol:Value()) self.linecol:Enable(self.chklinecol:Value()) elseif (msg > SS_Overlayer.TCMode_) and (msg <= SS_Overlayer.TCModeMax_) then self:HandleMessage(self.UPDATE) elseif (msg == self.FACTOR) then self.framefactor:SetValue(LM.Clamp(self.framefactor:Value(), 0, 999)) if (self.framefactor:Value() + 0 == 0) then self.framefactor:SetValue(1) end elseif (msg == self.RESET) then SS_Overlayer:ResetPrefs() self.timecodemodeMenu:UncheckAll() self:UpdateWidgets() self.timecodemodePopup:Redraw() SS_Overlayer.vecLayer:SetEditOnly(SS_Overlayer.rendermenot) elseif (msg == self.REMOVE) then SS_Overlayer.removeMe = true self.removeButt:SetLabel("*Remove", false) end end function SS_Overlayer_Dialog:OnOK() SS_Overlayer.prefix = self.prefix:Value() SS_Overlayer.postfix = self.postfix:Value() SS_Overlayer.linewid = LM.Clamp(self.linewid:FloatValue(), 0.25, 256) SS_Overlayer.fontsize = LM.Clamp(self.fontsize:Value(), 10, 200) SS_Overlayer.nameoverlay = self.nameoverlay:Value() SS_Overlayer.frameoffset = self.frameoffset:Value() + 0 SS_Overlayer.framefactor = self.framefactor:Value() + 0 SS_Overlayer.chkfillcol = self.chkfillcol:Value() SS_Overlayer.chklinecol = self.chklinecol:Value() SS_Overlayer.fillcol = self.fillcol:Value() SS_Overlayer.linecol = self.linecol:Value() SS_Overlayer.expression = self.expression:Value() SS_Overlayer.timecodemode = self.timecodemodeMenu:FirstCheckedMsg() - SS_Overlayer.TCMode_ SS_Overlayer.fontname = self.fontList:SelItemLabel() SS_Overlayer.label = self.label:Value() SS_Overlayer.rendermenot = not self.renderMeChk:Value() SS_Overlayer.vecLayer:SetEditOnly(SS_Overlayer.rendermenot) end
SS - Overlayer
Unlisted
Author: simplsam
View Script
Script type: Button/Menu
Uploaded: Jan 25 2024, 23:30
Timecode Counter and Custom Text - Graphical Overlays
Create Counter and Text based Graphical Overlays
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: 25
SS - Overlayer
Unlisted
Author: simplsam
View Script
Script type: Button/Menu
Uploaded: Jan 25 2024, 23:30
Timecode Counter and Custom Text - Graphical Overlays
Create Counter and Text based Graphical Overlays
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: 25