Image
-- ****************************************************
-- 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

Icon
SS - Overlayer
Unlisted

Script type: Button/Menu

Uploaded: Jan 25 2024, 23:30

Timecode Counter and Custom Text - Graphical Overlays
Create Counter and Text based Graphical Overlays

Installation Options:

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