1- using System . Collections ;
2- using System . Collections . Specialized ;
3- using System . ComponentModel ;
4- using System . Diagnostics ;
5- using System . Globalization ;
6- using System . IO ;
7- using System . Runtime . Serialization ;
8- using System . Timers ;
9- using System . Windows . Forms . Integration ;
10- using System . Xml ;
11- using Common . AudioPlayer ;
1+ using Common . AudioPlayer ;
2+ using Common . Broadcast ;
123using Common . Controls ;
134using Common . Controls . Scaling ;
145using Common . Controls . Theme ;
189using Common . Resources ;
1910using Common . Resources . Properties ;
2011using NLog ;
12+ using System . Collections ;
13+ using System . Collections . Specialized ;
14+ using System . ComponentModel ;
15+ using System . Diagnostics ;
16+ using System . Globalization ;
17+ using System . IO ;
18+ using System . Reflection . Metadata ;
19+ using System . Runtime . Serialization ;
20+ using System . Text . Json ;
21+ using System . Text . Json . Serialization ;
22+ using System . Timers ;
23+ using System . Windows . Forms . Integration ;
24+ using System . Xml ;
2125using Vixen ;
2226using Vixen . Execution ;
2327using Vixen . Execution . Context ;
2428using Vixen . Marks ;
2529using Vixen . Module ;
2630using Vixen . Module . App ;
27- using VixenModules . App . Curves ;
28- using VixenModules . App . LipSyncApp ;
29- using VixenModules . Effect . Effect ;
30- using VixenModules . Effect . Picture ;
31- using VixenModules . Effect . Shapes ;
32- using VixenModules . Media . Audio ;
33- using VixenModules . Effect . LipSync ;
3431using Vixen . Module . Editor ;
3532using Vixen . Module . Effect ;
3633using Vixen . Module . Media ;
3936using Vixen . Sys ;
4037using Vixen . Sys . LayerMixing ;
4138using VixenModules . App . ColorGradients ;
39+ using VixenModules . App . Curves ;
40+ using VixenModules . App . LipSyncApp ;
4241using VixenModules . App . Marks ;
43- using VixenModules . Editor . EffectEditor ;
4442using VixenModules . App . TimedSequenceMapper . SequenceElementMapper . ViewModels ;
4543using VixenModules . App . TimedSequenceMapper . SequenceElementMapper . Views ;
44+ using VixenModules . Editor . EffectEditor ;
4645using VixenModules . Editor . TimedSequenceEditor . Undo ;
46+ using VixenModules . Effect . Effect ;
47+ using VixenModules . Effect . LipSync ;
48+ using VixenModules . Effect . Picture ;
49+ using VixenModules . Effect . Shapes ;
50+ using VixenModules . Media . Audio ;
51+ using VixenModules . Property . Color ;
4752using VixenModules . Sequence . Timed ;
4853using WeifenLuo . WinFormsUI . Docking ;
49- using Element = Common . Controls . Timeline . Element ;
50- using Timer = System . Windows . Forms . Timer ;
51- using VixenModules . Property . Color ;
54+ using Cursors = System . Windows . Forms . Cursors ;
5255using DockPanel = WeifenLuo . WinFormsUI . Docking . DockPanel ;
56+ using Element = Common . Controls . Timeline . Element ;
5357using ListView = System . Windows . Forms . ListView ;
5458using ListViewItem = System . Windows . Forms . ListViewItem ;
5559using MarkCollection = VixenModules . App . Marks . MarkCollection ;
56- using Cursors = System . Windows . Forms . Cursors ;
5760using MouseEventArgs = System . Windows . Forms . MouseEventArgs ;
5861using PropertyDescriptor = System . ComponentModel . PropertyDescriptor ;
5962using Size = System . Drawing . Size ;
60- using Common . Broadcast ;
63+ using Timer = System . Windows . Forms . Timer ;
6164
6265namespace VixenModules . Editor . TimedSequenceEditor
6366{
@@ -2150,7 +2153,7 @@ protected override void WndProc(ref Message m)
21502153
21512154 Debug . WriteLine ( "WindowProc DRAWCLIPBOARD: " + m . Msg , "WndProc" ) ;
21522155
2153- if ( ClipboardHasData ( ) )
2156+ if ( ClipboardHasTimelineElementData ( ) )
21542157 {
21552158 _TimeLineSequenceClipboardContentsChanged ( EventArgs . Empty ) ;
21562159 }
@@ -3463,33 +3466,6 @@ private void CursorMovedHandler(object sender, EventArgs e)
34633466 }
34643467 }
34653468
3466- private void UpdatePasteMenuStates ( )
3467- {
3468- editToolStripButton_Paste . Enabled = toolStripMenuItem_Paste . Enabled = GetClipboardCount ( ) > 0 ;
3469- editToolStripButton_PasteVisibleMarks . Visible = toolStripMenuItem_PasteToMarks . Enabled = GetMarksPresent ( ) && GetClipboardCount ( ) > 0 ;
3470- editToolStripButton_PasteInvert . Visible = toolStripMenuItem_PasteInvert . Enabled = GetClipboardCount ( ) > 1 ;
3471- editToolStripButton_PasteDropDown . Enabled = toolStripMenuItem_PasteSpecial . Enabled =
3472- toolStripMenuItem_PasteToMarks . Enabled || toolStripMenuItem_PasteInvert . Enabled ;
3473- }
3474-
3475- private bool ClipboardHasData ( )
3476- {
3477- IDataObject dataObject = Clipboard . GetDataObject ( ) ;
3478- return dataObject != null && dataObject . GetDataPresent ( ClipboardFormatName . Name ) ;
3479- }
3480-
3481- private int GetClipboardCount ( )
3482- {
3483- // Gets number of Effects on the clipboard, used to determine which paste options will be enabled.
3484- IDataObject dataObject = Clipboard . GetDataObject ( ) ;
3485- if ( dataObject . GetDataPresent ( ClipboardFormatName . Name ) )
3486- {
3487- if ( dataObject . GetData ( ClipboardFormatName . Name ) is TimelineElementsClipboardData data )
3488- return data . EffectModelCandidates . Count ;
3489- }
3490- return 0 ;
3491- }
3492-
34933469 private bool GetMarksPresent ( )
34943470 {
34953471 // Checks if there are any visible marks that are past the mouse click position.
@@ -4965,6 +4941,72 @@ protected override void OnFormClosed(FormClosedEventArgs e)
49654941
49664942 #region Clipboard
49674943
4944+ private void UpdatePasteMenuStates ( )
4945+ {
4946+ var count = GetTimelineElementsClipboardEffectCount ( ) ;
4947+ editToolStripButton_Paste . Enabled = toolStripMenuItem_Paste . Enabled = count > 0 ;
4948+ editToolStripButton_PasteVisibleMarks . Visible = toolStripMenuItem_PasteToMarks . Enabled = GetMarksPresent ( ) && count > 0 ;
4949+ editToolStripButton_PasteInvert . Visible = toolStripMenuItem_PasteInvert . Enabled = count > 1 ;
4950+ editToolStripButton_PasteDropDown . Enabled = toolStripMenuItem_PasteSpecial . Enabled =
4951+ toolStripMenuItem_PasteToMarks . Enabled || toolStripMenuItem_PasteInvert . Enabled ;
4952+ }
4953+
4954+ /// <summary>
4955+ /// Determines whether the clipboard contains data in the timeline element format.
4956+ /// </summary>
4957+ /// <returns>true if the clipboard contains data in the timeline element format; otherwise, false.</returns>
4958+ private bool ClipboardHasTimelineElementData ( )
4959+ {
4960+ return Clipboard . ContainsData ( ClipboardFormatName . Name ) ;
4961+ }
4962+
4963+ /// <summary>
4964+ /// Gets the number of effect model candidates available in the clipboard timeline elements.
4965+ /// </summary>
4966+ /// <remarks>Call this method to determine how many effect model candidates are currently available from the
4967+ /// clipboard timeline elements. Ensure that the clipboard contains valid timeline data before relying on the returned
4968+ /// count.</remarks>
4969+ /// <returns>The number of effect model candidates in the clipboard timeline elements. Returns 0 if no clipboard data is
4970+ /// present.</returns>
4971+ private int GetTimelineElementsClipboardEffectCount ( )
4972+ {
4973+ var timelineData = GetTimelineElementsClipboardData ( ) ;
4974+ return timelineData != null ? timelineData . EffectModelCandidates . Count : 0 ;
4975+ }
4976+
4977+ /// <summary>
4978+ /// Retrieves timeline elements data from the clipboard if available in the expected format.
4979+ /// </summary>
4980+ /// <remarks>This method checks whether the clipboard contains data in the specified timeline elements format
4981+ /// before attempting to retrieve it. Callers should verify the return value for <see langword="null"/> to determine
4982+ /// if valid data was retrieved.</remarks>
4983+ /// <returns>A <see cref="TimelineElementsClipboardData"/> instance containing the timeline elements from the clipboard; or
4984+ /// <see langword="null"/> if the clipboard does not contain data in the required format.</returns>
4985+ private TimelineElementsClipboardData GetTimelineElementsClipboardData ( )
4986+ {
4987+ if ( ClipboardHasTimelineElementData ( ) )
4988+ {
4989+ if ( Clipboard . TryGetData < TimelineElementsClipboardData > ( ClipboardFormatName . Name , out var timelineData ) )
4990+ {
4991+ return timelineData ;
4992+ }
4993+ }
4994+ return null ;
4995+ }
4996+
4997+ /// <summary>
4998+ /// Sets the clipboard data for timeline elements using the specified data object.
4999+ /// </summary>
5000+ /// <remarks>This method serializes the provided data as JSON and stores it in the clipboard under a specific
5001+ /// format. Ensure that the data object is valid before calling this method.</remarks>
5002+ /// <param name="data">The timeline elements clipboard data to be serialized and placed on the clipboard.</param>
5003+ private void SetTimelineElementsClipboardData ( TimelineElementsClipboardData data )
5004+ {
5005+ ArgumentNullException . ThrowIfNull ( data ) ;
5006+ Clipboard . SetDataAsJson ( ClipboardFormatName . Name , data ) ;
5007+ //_TimeLineSequenceClipboardContentsChanged(EventArgs.Empty);
5008+ }
5009+
49685010 private void ClipboardAddData ( bool cutElements )
49695011 {
49705012 if ( ! TimelineControl . SelectedElements . Any ( ) )
@@ -4983,12 +5025,11 @@ private void ClipboardAddData(bool cutElements)
49835025 foreach ( Row row in TimelineControl . VisibleRows )
49845026 {
49855027 //Check that the same Row name has not already been processed and will skip if the same Row is found visible in another group.
4986- if ( uniqueStrings . Contains ( row . Name ) ) continue ;
4987- uniqueStrings . Add ( row . Name ) ;
5028+ if ( ! uniqueStrings . Add ( row . Name ) ) continue ;
49885029
49895030 // Since removals may happen during enumeration, make a copy with ToArray().
49905031
4991- //If we already have the elements becasue the same row is duplicated then skip.
5032+ //If we already have the elements because the same row is duplicated then skip.
49925033 if ( affectedElements . Intersect ( row . SelectedElements ) . Any ( ) )
49935034 {
49945035 rownum ++ ;
@@ -5012,7 +5053,7 @@ private void ClipboardAddData(bool cutElements)
50125053 LayerName = layer . LayerName ,
50135054 LayerTypeId = layer . FilterTypeId
50145055 } ;
5015- result . EffectModelCandidates . Add ( modelCandidate , relativeVisibleRow ) ;
5056+ result . EffectModelCandidates . Add ( new EffectModelRecord ( modelCandidate , relativeVisibleRow ) ) ;
50165057
50175058 if ( elem . StartTime < result . EarliestStartTime )
50185059 result . EarliestStartTime = elem . StartTime ;
@@ -5030,12 +5071,8 @@ private void ClipboardAddData(bool cutElements)
50305071 var act = new EffectsCutUndoAction ( this , affectedElements . Select ( x => x . EffectNode ) ) ;
50315072 _undoMgr . AddUndoAction ( act ) ;
50325073 }
5033-
50345074
5035- IDataObject dataObject = new DataObject ( ClipboardFormatName ) ;
5036- dataObject . SetData ( result ) ;
5037- Clipboard . SetDataObject ( dataObject , true ) ;
5038- _TimeLineSequenceClipboardContentsChanged ( EventArgs . Empty ) ;
5075+ SetTimelineElementsClipboardData ( result ) ;
50395076 }
50405077
50415078 private void ClipboardCut ( )
@@ -5056,32 +5093,23 @@ private void ClipboardCopy()
50565093 public int ClipboardPaste ( TimeSpan pasteTime )
50575094 {
50585095 int result = 0 ;
5059- TimelineElementsClipboardData data = null ;
5060- IDataObject dataObject = Clipboard . GetDataObject ( ) ;
5061-
5062- if ( dataObject == null )
5063- return result ;
5064-
5065- if ( dataObject . GetDataPresent ( ClipboardFormatName . Name ) )
5066- {
5067- data = dataObject . GetData ( ClipboardFormatName . Name ) as TimelineElementsClipboardData ;
5068- }
5069-
5096+ TimelineElementsClipboardData data = GetTimelineElementsClipboardData ( ) ;
5097+
50705098 if ( data == null )
50715099 {
50725100 return result ;
50735101 }
50745102
50755103 List < int > index = new List < int > ( ) ;
50765104 List < TimeSpan > markStartTimes = new List < TimeSpan > ( ) ;
5077- List < KeyValuePair < EffectModelCandidate , int > > effects ;
5105+ List < EffectModelRecord > effects ;
50785106 switch ( PastingMode )
50795107 {
50805108 case PastingMode . VisibleMarks :
50815109 {
50825110 // We need to order the effects by Start time as they are currently ordered by Row index first which is
50835111 // no good for pasting to Mark Collection or Visible Marks.
5084- effects = data . EffectModelCandidates . OrderBy ( x => ( x . Key . StartTime ) ) . ToList ( ) ;
5112+ effects = data . EffectModelCandidates . OrderBy ( x => ( x . EffectModel . StartTime ) ) . ToList ( ) ;
50855113 for ( int i = 0 ; i < _sequence . LabeledMarkCollections . Count ; i ++ )
50865114 {
50875115 // Only continue process visible Mark collections
@@ -5112,9 +5140,9 @@ public int ClipboardPaste(TimeSpan pasteTime)
51125140 break ;
51135141 }
51145142 case PastingMode . Invert :
5115- foreach ( KeyValuePair < EffectModelCandidate , int > order in data . EffectModelCandidates )
5143+ foreach ( EffectModelRecord order in data . EffectModelCandidates )
51165144 {
5117- index . Add ( data . EffectModelCandidates . Last ( ) . Value - order . Value ) ;
5145+ index . Add ( data . EffectModelCandidates . Last ( ) . RowOffset - order . RowOffset ) ;
51185146 }
51195147 effects = data . EffectModelCandidates . ToList ( ) ;
51205148 break ;
@@ -5131,10 +5159,10 @@ public int ClipboardPaste(TimeSpan pasteTime)
51315159 List < Row > visibleRows = new List < Row > ( TimelineControl . VisibleRows ) ;
51325160 int topTargetRoxIndex = visibleRows . IndexOf ( targetRow ) ;
51335161 List < EffectNode > nodesToAdd = new List < EffectNode > ( ) ;
5134- foreach ( KeyValuePair < EffectModelCandidate , int > kvp in effects )
5162+ foreach ( EffectModelRecord effectModelRecord in effects )
51355163 {
5136- EffectModelCandidate effectModelCandidate = kvp . Key ;
5137- int relativeRow = kvp . Value ;
5164+ EffectModelCandidate effectModelCandidate = effectModelRecord . EffectModel ;
5165+ int relativeRow = effectModelRecord . RowOffset ;
51385166 TimeSpan targetTime = effectModelCandidate . StartTime - offset + pasteTime ;
51395167 switch ( PastingMode )
51405168 {
@@ -5932,15 +5960,14 @@ private void textConverterHandler(object sender, NewTranslationEventArgs args)
59325960 Duration = data . Duration ,
59335961 StartTime = data . StartOffset
59345962 } ;
5935- result . EffectModelCandidates . Add ( modelCandidate , 0 ) ;
5963+ result . EffectModelCandidates . Add ( new EffectModelRecord ( modelCandidate , 0 ) ) ;
59365964 if ( data . StartOffset < result . EarliestStartTime )
59375965 result . EarliestStartTime = data . StartOffset ;
59385966 effect . PreRender ( ) ;
59395967 }
5940- IDataObject dataObject = new DataObject ( ClipboardFormatName ) ;
5941- dataObject . SetData ( result ) ;
5942- Clipboard . SetDataObject ( dataObject , true ) ;
5943- _TimeLineSequenceClipboardContentsChanged ( EventArgs . Empty ) ;
5968+
5969+ SetTimelineElementsClipboardData ( result ) ;
5970+
59445971 int pasted = 0 ;
59455972 if ( args . Placement == TranslatePlacement . Cursor )
59465973 {
@@ -6156,20 +6183,19 @@ public TimeSpan GetDefaultEffectDuration(TimeSpan startTime,bool visibleDuration
61566183 }
61576184 }
61586185
6159- [ Serializable ]
61606186 internal class TimelineElementsClipboardData
61616187 {
6162- public TimelineElementsClipboardData ( )
6163- {
6164- EffectModelCandidates = new Dictionary < EffectModelCandidate , int > ( ) ;
6165- }
6166-
61676188 // a collection of elements and the number of rows they were below the top visible element when
61686189 // this data was generated and placed on the clipboard.
6169- public Dictionary < EffectModelCandidate , int > EffectModelCandidates { get ; set ; }
6190+ public List < EffectModelRecord > EffectModelCandidates { get ; init ; } = new ( ) ;
61706191
61716192 public int FirstVisibleRow { get ; set ; }
61726193
61736194 public TimeSpan EarliestStartTime { get ; set ; }
61746195 }
6196+
6197+ internal record EffectModelRecord ( EffectModelCandidate EffectModel , int RowOffset )
6198+ {
6199+
6200+ }
61756201}
0 commit comments