Learning how to convert a script to Custom Command

Thiago_Sase wrote on 10/7/2024, 9:00 AM

@jetdv Hello, Sir, please, if possible, could you help me? I'm watching your tutorials' series of Build a Custom Command, and I'm trying to convert my scripts to a custom command. But, I'm always getting the same error;


"An error occured: Catastrophic failure (Excepetion from HRESULT: 0x8000FFFF {E_UNEXPECTED})"

This is the CCMainForm.cs;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ScriptPortal.Vegas;

namespace CCTest
{

    public partial class CCMainForm : UserControl
    {
        Vegas myVegas;

        public CCMainForm(Vegas vegas)
        {
            myVegas = vegas;

            InitializeComponent();

            // Populate the ComboBox with the options "Frames", "Seconds", and "Minutes"
            SelectUnitComboBox.Items.Add("Frames");
            SelectUnitComboBox.Items.Add("Seconds");
            SelectUnitComboBox.Items.Add("Minutes");

            // Optionally, set a default selection
            SelectUnitComboBox.SelectedIndex = 0; // "Frames" selected by default
            // Set default value for numericUpDown1 to 42
            numericUpDown1.Value = 42;
        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            // Get the numeric up-down control that triggered the event
            NumericUpDown inputBox = sender as NumericUpDown;

            // Check if inputBox is not null
            if (inputBox != null)
            {
                // Ensure the value is between 1 and 1000
                int value = (int)inputBox.Value;

                // You can now use this value for whatever logic you need
                // For example: simple logic that uses the value
                if (value >= 1 && value <= 1000)
                {
                    // Value is valid, do something here if needed
                    // (e.g., pass it to another method or store it)
                    Console.WriteLine("Set value: " + value);
                }
                
            }
        }

        private void SelectUnitComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Get the selected unit from the ComboBox
            string selectedUnit = SelectUnitComboBox.SelectedItem.ToString();

            // Get the amount value from the numericUpDown control
            int amount = (int)numericUpDown1.Value;

            // Define the Timecode offset
            Timecode offset;

            // Apply the logic based on the selected unit
            try
            {
                if (selectedUnit == "Frames")
                {
                    offset = Timecode.FromFrames(amount);
                }
                else if (selectedUnit == "Seconds")
                {
                    offset = Timecode.FromSeconds(amount);
                }
                else if (selectedUnit == "Minutes")
                {
                    offset = Timecode.FromSeconds(amount * 60); // Convert minutes to seconds
                }
                else
                {
                    throw new ArgumentException("Invalid time unit selected.");
                }

                // Do something with the calculated offset, e.g., store or display it
                Console.WriteLine($"Offset calculated: {offset}");
            }
            catch (ArgumentException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void MoveLeftButton_Click(object sender, EventArgs e)
        {
            // Call MoveEventsLeft when "Move Left" button is clicked
            MoveEventsLeft(myVegas);
        }

        void MoveEventsLeft(Vegas vegas)
        {
            // Retrieve the current value from numericUpDown1 (amount)
            int amount = (int)numericUpDown1.Value;

            // Retrieve the selected unit from SelectUnitComboBox
            string selectedUnit = SelectUnitComboBox.SelectedItem.ToString();

            // Determine the time offset based on the selected unit (Frames, Seconds, or Minutes)
            Timecode offset;
            if (selectedUnit == "Frames")
            {
                offset = Timecode.FromFrames(amount);
            }
            else if (selectedUnit == "Seconds")
            {
                offset = Timecode.FromSeconds(amount);
            }
            else if (selectedUnit == "Minutes")
            {
                offset = Timecode.FromSeconds(amount * 60); // Convert minutes to seconds
            }
            else
            {
                throw new ArgumentException("Invalid time unit specified.");
            }

            // Collect all selected events across all tracks
            var allSelectedEvents = new List<TrackEvent>();
            var processedEvents = new List<TrackEvent>(); // To track processed events

            // Iterate over each track to gather selected events
            foreach (Track track in vegas.Project.Tracks)
            {
                foreach (TrackEvent trackEvent in track.Events)
                {
                    if (trackEvent.Selected)
                    {
                        allSelectedEvents.Add(trackEvent);
                    }
                }
            }

            // Move all selected events left
            foreach (TrackEvent trackEvent in allSelectedEvents)
            {
                try
                {
                    if (processedEvents.Contains(trackEvent)) continue;

                    // Move the selected event left
                    trackEvent.Start -= offset;
                    FixUnquantizedFrames(trackEvent); // Fix unquantized frames

                    processedEvents.Add(trackEvent); // Mark as processed

                    // Handle grouped events
                    if (trackEvent.Group != null)
                    {
                        foreach (TrackEvent groupedEvent in trackEvent.Group)
                        {
                            if (processedEvents.Contains(groupedEvent)) continue; // Avoid moving grouped events twice

                            // Move grouped event left
                            groupedEvent.Start -= offset;
                            FixUnquantizedFrames(groupedEvent); // Fix unquantized frames
                            processedEvents.Add(groupedEvent); // Mark as processed
                        }
                    }
                }
                catch (System.Security.SecurityException ex)
                {
                    MessageBox.Show("A security exception occurred: " + ex.Message);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("An error occurred: " + ex.Message);
                }
            }

            // Optionally move Volume Envelope Points left (if needed)
            foreach (Track track in vegas.Project.Tracks)
            {
                MoveVolumeEnvelopePointsLeft(track, offset);
            }

            vegas.UpdateUI(); // Refresh UI to reflect changes immediately
        }

        // Method to move volume envelope points left (optional)
        private void MoveVolumeEnvelopePointsLeft(Track track, Timecode offset)
        {
            foreach (Envelope envelope in track.Envelopes)
            {
                if (envelope.Type == EnvelopeType.Volume)
                {
                    for (int i = 0; i < envelope.Points.Count; i++)
                    {
                        EnvelopePoint point = envelope.Points[i];
                        point.X = point.X - offset; // Move point left
                    }
                }
            }
        }

        // Method to fix unquantized frames for both video and audio events
        private void FixUnquantizedFrames(TrackEvent evt)
        {
            if (evt == null) return;

            double frameRate = myVegas.Project.Video.FrameRate;
            double frameDurationMs = 1000.0 / frameRate; // Frame duration in milliseconds

            // Adjust start time to nearest frame
            double startMs = evt.Start.ToMilliseconds();
            evt.Start = new Timecode(Math.Round(startMs / frameDurationMs) * frameDurationMs);

            // Adjust length to nearest frame
            double lengthMs = evt.Length.ToMilliseconds();
            evt.Length = new Timecode(Math.Round(lengthMs / frameDurationMs) * frameDurationMs);
        }

    }
}

And this is the CCTest.cs;

 

using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using System.Drawing;
using System.Runtime;
using System.Xml;
using System.Windows.Forms;
using ScriptPortal.Vegas;


namespace CCTest
{
    public class CCTestDock : DockableControl
    {
        private CCTest.CCMainForm myform = null;

        public CCTestDock() : base("CCTestInternal")
        {
            this.DisplayName = "CCTest";
        }

        public override DockWindowStyle DefaultDockWindowStyle
        {
            get { return DockWindowStyle.Docked; }
        }

        public override Size DefaultFloatingSize
        {
            get { return new Size(640, 480); }
        }

        protected override void OnLoad(EventArgs args)
        {
            myform = new CCTest.CCMainForm(myVegas);
            myform.Dock = DockStyle.Fill;
            this.Controls.Add(myform);
        }

        protected override void OnClosed(EventArgs args)
        {
            base.OnClosed(args);
        }
    }
}

public class CCTestCCM : ICustomCommandModule
{
    public Vegas myVegas = null;
    CustomCommand CCM = new CustomCommand(CommandCategory.View, "CCTest");

    public void InitializeModule(Vegas vegas)
    {
        myVegas = vegas;

        CCM.MenuItemName = "My Test Custom Command";
    }

    public ICollection GetCustomCommands()
    {
        CCM.MenuPopup += this.HandlePICmdMenuPopup;
        CCM.Invoked += this.HandlePICmdInvoked;
        CustomCommand[] cmds = new CustomCommand[] { CCM };
        return cmds;
    }

    void HandlePICmdMenuPopup(Object sender, EventArgs args)
    {
        CCM.Checked = myVegas.FindDockView("CCTestInternal");
    }

    void HandlePICmdInvoked(Object sender, EventArgs args)
    {
        if (!myVegas.ActivateDockView("CCTestInternal"))
        {
            CCTest.CCTestDock CCMDock = new CCTest.CCTestDock();
            CCMDock.AutoLoadCommand = CCM;
            CCMDock.PersistDockWindowState = true;
            myVegas.LoadDockView(CCMDock);
        }
    }
}


And this is the photo of the Form I'm creating to be like my original script;


 

The Move Right button is not ready yet. I'm trying to make the Move Left button works first. But Always getting that error.

In my original Script works fine. But, trying to adapt to a custom command, I'm getting this issue.


Please, Sir, where is my mistake?

Comments

jetdv wrote on 10/7/2024, 9:09 AM

@Thiago_Sase With a custom command, any of the routines that change VEGAS have to be enclosed in an "UndoBlock".

Thiago_Sase wrote on 10/7/2024, 9:37 AM

@jetdv Thank you very much, Sir.

This line of code;

using (new UndoBlock("Move Events Left"))

Made the button worked.

I jumped part 4 of the series by mistake. Now, I'm watching carefully.

Thank you!