diff --git a/Source/Editor/Cooker/CookingData.h b/Source/Editor/Cooker/CookingData.h
index 8c1113f71..fbe245619 100644
--- a/Source/Editor/Cooker/CookingData.h
+++ b/Source/Editor/Cooker/CookingData.h
@@ -137,7 +137,7 @@ extern FLAXENGINE_API const Char* ToString(const BuildConfiguration configuratio
///
/// Game cooking temporary data.
///
-API_CLASS(Sealed, Namespace="FlaxEditor") class FLAXENGINE_API CookingData : public PersistentScriptingObject
+API_CLASS(Sealed, Namespace="FlaxEditor") class FLAXENGINE_API CookingData : public ScriptingObject
{
DECLARE_SCRIPTING_TYPE(CookingData);
public:
diff --git a/Source/Editor/Cooker/GameCooker.cpp b/Source/Editor/Cooker/GameCooker.cpp
index d70fc523f..ef51bb0d0 100644
--- a/Source/Editor/Cooker/GameCooker.cpp
+++ b/Source/Editor/Cooker/GameCooker.cpp
@@ -171,7 +171,7 @@ CookingData::Statistics::Statistics()
}
CookingData::CookingData(const SpawnParams& params)
- : PersistentScriptingObject(params)
+ : ScriptingObject(params)
{
}
diff --git a/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp b/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp
index d399c7f63..c74368348 100644
--- a/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp
@@ -179,12 +179,12 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (file)
{
auto now = DateTime::Now();
- file->WriteTextFormatted(
+ file->WriteText(StringAnsi::Format(
fileTemplate.Get()
, gameSettings->ProductName.ToStringAnsi()
, gameSettings->CompanyName.ToStringAnsi()
, now.GetYear()
- );
+ ));
hasError = file->HasError();
Delete(file);
}
@@ -210,10 +210,10 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
bool hasError = true;
if (file)
{
- file->WriteTextFormatted(
+ file->WriteText(StringAnsi::Format(
fileTemplate.Get()
, defaultNamespace.ToStringAnsi() // {0} Default Namespace
- );
+ ));
hasError = file->HasError();
Delete(file);
}
@@ -264,11 +264,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
bool hasError = true;
if (file)
{
- file->WriteTextFormatted(
+ file->WriteText(StringAnsi::Format(
fileTemplate.Get()
, autoRotationPreferences.Get()
, preferredLaunchWindowingMode.Get()
- );
+ ));
hasError = file->HasError();
Delete(file);
}
@@ -296,12 +296,12 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
bool hasError = true;
if (file)
{
- file->WriteTextFormatted(
+ file->WriteText(StringAnsi::Format(
fileTemplate.Get()
, projectName.ToStringAnsi() // {0} Project Name
, mode // {1} Platform Mode
, projectGuid.ToStringAnsi() // {2} Project ID
- );
+ ));
hasError = file->HasError();
Delete(file);
}
@@ -344,14 +344,14 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
bool hasError = true;
if (file)
{
- file->WriteTextFormatted(
+ file->WriteText(StringAnsi::Format(
fileTemplate.Get()
, projectName.ToStringAnsi() // {0} Project Name
, mode // {1} Platform Mode
, projectGuid.Get() // {2} Project ID
, filesInclude.ToString().ToStringAnsi() // {3} Files to include
, defaultNamespace.ToStringAnsi() // {4} Default Namespace
- );
+ ));
hasError = file->HasError();
Delete(file);
}
@@ -394,13 +394,13 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
bool hasError = true;
if (file)
{
- file->WriteTextFormatted(
+ file->WriteText(StringAnsi::Format(
fileTemplate.Get()
, projectName.ToStringAnsi() // {0} Display Name
, gameSettings->CompanyName.ToStringAnsi() // {1} Company Name
, productId.ToStringAnsi() // {2} Product ID
, defaultNamespace.ToStringAnsi() // {3} Default Namespace
- );
+ ));
hasError = file->HasError();
Delete(file);
}
diff --git a/Source/Editor/CustomEditors/SyncPointEditor.cs b/Source/Editor/CustomEditors/SyncPointEditor.cs
index 3555aaea4..8d8b85f2a 100644
--- a/Source/Editor/CustomEditors/SyncPointEditor.cs
+++ b/Source/Editor/CustomEditors/SyncPointEditor.cs
@@ -102,6 +102,16 @@ namespace FlaxEditor.CustomEditors
///
protected virtual void OnModified()
{
+ var parent = ParentEditor;
+ while (parent != null)
+ {
+ if (parent is SyncPointEditor syncPointEditor)
+ {
+ syncPointEditor.OnModified();
+ break;
+ }
+ parent = parent.ParentEditor;
+ }
}
///
diff --git a/Source/Editor/GUI/Timeline/AnimationTimeline.cs b/Source/Editor/GUI/Timeline/AnimationTimeline.cs
index 50e5ddfdb..19c1543e0 100644
--- a/Source/Editor/GUI/Timeline/AnimationTimeline.cs
+++ b/Source/Editor/GUI/Timeline/AnimationTimeline.cs
@@ -52,7 +52,7 @@ namespace FlaxEditor.GUI.Timeline
///
/// The undo/redo to use for the history actions recording. Optional, can be null to disable undo support.
public AnimationTimeline(FlaxEditor.Undo undo)
- : base(PlaybackButtons.Play | PlaybackButtons.Stop, undo, false, false)
+ : base(PlaybackButtons.Play | PlaybackButtons.Stop, undo, false, true)
{
PlaybackState = PlaybackStates.Seeking;
ShowPreviewValues = false;
@@ -61,6 +61,7 @@ namespace FlaxEditor.GUI.Timeline
// Setup track types
TrackArchetypes.Add(AnimationChannelTrack.GetArchetype());
TrackArchetypes.Add(AnimationChannelDataTrack.GetArchetype());
+ TrackArchetypes.Add(AnimationEventTrack.GetArchetype());
}
///
diff --git a/Source/Editor/GUI/Timeline/GUI/Background.cs b/Source/Editor/GUI/Timeline/GUI/Background.cs
index 26c5e65ee..cfe7986c0 100644
--- a/Source/Editor/GUI/Timeline/GUI/Background.cs
+++ b/Source/Editor/GUI/Timeline/GUI/Background.cs
@@ -16,8 +16,8 @@ namespace FlaxEditor.GUI.Timeline.GUI
private readonly Timeline _timeline;
private float[] _tickSteps;
private float[] _tickStrengths;
- private bool _leftMouseDown;
- private Vector2 _leftMouseDownPos = Vector2.Minimum;
+ private bool _isSelecting;
+ private Vector2 _selectingStartPos = Vector2.Minimum;
private Vector2 _mousePos = Vector2.Minimum;
///
@@ -33,7 +33,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
private void UpdateSelectionRectangle()
{
- var selectionRect = Rectangle.FromPoints(_leftMouseDownPos, _mousePos);
+ var selectionRect = Rectangle.FromPoints(_selectingStartPos, _mousePos);
_timeline.OnKeyframesSelection(null, this, selectionRect);
}
@@ -41,20 +41,17 @@ namespace FlaxEditor.GUI.Timeline.GUI
public override bool OnMouseDown(Vector2 location, MouseButton button)
{
if (base.OnMouseDown(location, button))
- {
- _leftMouseDown = false;
return true;
- }
_mousePos = location;
if (button == MouseButton.Left)
{
// Start selecting
- _leftMouseDown = true;
- _leftMouseDownPos = location;
- StartMouseCapture();
+ _isSelecting = true;
+ _selectingStartPos = location;
_timeline.OnKeyframesDeselect(null);
Focus();
+ StartMouseCapture();
return true;
}
@@ -65,19 +62,16 @@ namespace FlaxEditor.GUI.Timeline.GUI
public override bool OnMouseUp(Vector2 location, MouseButton button)
{
_mousePos = location;
-
- if (_leftMouseDown && button == MouseButton.Left)
+ if (_isSelecting && button == MouseButton.Left)
{
// End selecting
- _leftMouseDown = false;
+ _isSelecting = false;
EndMouseCapture();
+ return true;
}
if (base.OnMouseUp(location, button))
- {
- _leftMouseDown = false;
return true;
- }
return true;
}
@@ -88,7 +82,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
_mousePos = location;
// Selecting
- if (_leftMouseDown)
+ if (_isSelecting)
{
UpdateSelectionRectangle();
return;
@@ -100,11 +94,24 @@ namespace FlaxEditor.GUI.Timeline.GUI
///
public override void OnLostFocus()
{
- _leftMouseDown = false;
+ if (_isSelecting)
+ {
+ _isSelecting = false;
+ EndMouseCapture();
+ }
base.OnLostFocus();
}
+ ///
+ public override void OnEndMouseCapture()
+ {
+ _isSelecting = false;
+ EndMouseCapture();
+
+ base.OnEndMouseCapture();
+ }
+
///
public override bool IntersectsContent(ref Vector2 locationParent, out Vector2 location)
{
@@ -217,9 +224,9 @@ namespace FlaxEditor.GUI.Timeline.GUI
}
// Draw selection rectangle
- if (_leftMouseDown)
+ if (_isSelecting)
{
- var selectionRect = Rectangle.FromPoints(_leftMouseDownPos, _mousePos);
+ var selectionRect = Rectangle.FromPoints(_selectingStartPos, _mousePos);
Render2D.FillRectangle(selectionRect, Color.Orange * 0.4f);
Render2D.DrawRectangle(selectionRect, Color.Orange);
}
diff --git a/Source/Editor/GUI/Timeline/Media.cs b/Source/Editor/GUI/Timeline/Media.cs
index 5fd390817..b97717ec8 100644
--- a/Source/Editor/GUI/Timeline/Media.cs
+++ b/Source/Editor/GUI/Timeline/Media.cs
@@ -91,7 +91,7 @@ namespace FlaxEditor.GUI.Timeline
/// The media.
protected ProxyBase(TTrack track, TMedia media)
{
- Track = track ?? throw new ArgumentNullException(nameof(track));
+ Track = track;
Media = media ?? throw new ArgumentNullException(nameof(media));
}
}
@@ -215,7 +215,7 @@ namespace FlaxEditor.GUI.Timeline
///
/// Gets a value indicating whether this media can be resized (duration changed).
///
- public bool CanResize;
+ public bool CanResize = true;
///
/// Initializes a new instance of the class.
@@ -229,8 +229,9 @@ namespace FlaxEditor.GUI.Timeline
/// Called when showing timeline context menu to the user. Can be used to add custom buttons.
///
/// The menu.
+ /// The time (in seconds) at which context menu is shown (user clicked on a timeline).
/// The found control under the mouse cursor.
- public virtual void OnTimelineShowContextMenu(ContextMenu.ContextMenu menu, Control controlUnderMouse)
+ public virtual void OnTimelineContextMenu(ContextMenu.ContextMenu menu, float time, Control controlUnderMouse)
{
if (CanDelete && Track.Media.Count > Track.MinMediaCount)
menu.AddButton("Delete media", Delete);
@@ -341,14 +342,15 @@ namespace FlaxEditor.GUI.Timeline
var style = Style.Current;
var bounds = new Rectangle(Vector2.Zero, Size);
- var fillColor = style.Background * 1.5f;
+ var fillColor = BackgroundColor.A > 0.0f ? BackgroundColor : style.Background * 1.5f;
Render2D.FillRectangle(bounds, fillColor);
var isMovingWholeMedia = _isMoving && !_startMoveRightEdge && !_startMoveLeftEdge;
var borderHighlightColor = style.BorderHighlighted;
var moveColor = style.ProgressNormal;
+ var selectedColor = style.BackgroundSelected;
var moveThickness = 2.0f;
- var borderColor = isMovingWholeMedia ? moveColor : (IsMouseOver ? borderHighlightColor : style.BorderNormal);
+ var borderColor = isMovingWholeMedia ? moveColor : (Timeline.SelectedMedia.Contains(this) ? selectedColor : (IsMouseOver ? borderHighlightColor : style.BorderNormal));
Render2D.DrawRectangle(bounds, borderColor, isMovingWholeMedia ? moveThickness : 1.0f);
if (_startMoveLeftEdge)
{
@@ -384,9 +386,26 @@ namespace FlaxEditor.GUI.Timeline
_startMoveDuration = DurationFrames;
_startMoveLeftEdge = MoveLeftEdgeRect.Contains(ref location) && CanResize;
_startMoveRightEdge = MoveRightEdgeRect.Contains(ref location) && CanResize;
-
StartMouseCapture(true);
+ if (_startMoveLeftEdge || _startMoveRightEdge)
+ return true;
+ if (Root.GetKey(KeyboardKeys.Control))
+ {
+ // Add/Remove selection
+ if (_timeline.SelectedMedia.Contains(this))
+ _timeline.Deselect(this);
+ else
+ _timeline.Select(this, true);
+ }
+ else
+ {
+ // Select
+ if (!_timeline.SelectedMedia.Contains(this))
+ _timeline.Select(this);
+ }
+
+ _timeline.OnKeyframesMove(null, this, location, true, false);
return true;
}
@@ -417,7 +436,8 @@ namespace FlaxEditor.GUI.Timeline
}
else
{
- StartFrame = _startMoveStartFrame + moveDelta;
+ // Move with global timeline selection
+ _timeline.OnKeyframesMove(null, this, location, false, false);
}
if (StartFrame != startFrame || DurationFrames != durationFrames)
@@ -436,6 +456,15 @@ namespace FlaxEditor.GUI.Timeline
{
if (button == MouseButton.Left && _isMoving)
{
+ if (!_startMoveLeftEdge && !_startMoveRightEdge && !Root.GetKey(KeyboardKeys.Control))
+ {
+ var moveLocationDelta = Root.MousePosition - _startMoveLocation;
+ if (moveLocationDelta.Length < 4.0f)
+ {
+ // No move so just select itself
+ _timeline.Select(this);
+ }
+ }
EndMoving();
return true;
}
@@ -443,6 +472,20 @@ namespace FlaxEditor.GUI.Timeline
return base.OnMouseUp(location, button);
}
+ ///
+ public override bool OnMouseDoubleClick(Vector2 location, MouseButton button)
+ {
+ if (base.OnMouseDoubleClick(location, button))
+ return true;
+
+ if (PropertiesEditObject != null)
+ {
+ Timeline.ShowEditPopup(PropertiesEditObject, PointToParent(Timeline, location), Track);
+ return true;
+ }
+ return false;
+ }
+
///
public override void OnEndMouseCapture()
{
@@ -484,22 +527,30 @@ namespace FlaxEditor.GUI.Timeline
private void EndMoving()
{
_isMoving = false;
- _startMoveLeftEdge = false;
- _startMoveRightEdge = false;
-
- // Re-assign the media start/duration inside the undo recording block
- if (_startMoveStartFrame != _startFrame || _startMoveDuration != _durationFrames)
+ if (_startMoveLeftEdge || _startMoveRightEdge)
{
- var endMoveStartFrame = _startFrame;
- var endMoveDuration = _durationFrames;
- _startFrame = _startMoveStartFrame;
- _durationFrames = _startMoveDuration;
- using (new TrackUndoBlock(_tack))
+ _startMoveLeftEdge = false;
+ _startMoveRightEdge = false;
+
+ // Re-assign the media start/duration inside the undo recording block
+ if (_startMoveStartFrame != _startFrame || _startMoveDuration != _durationFrames)
{
- _startFrame = endMoveStartFrame;
- _durationFrames = endMoveDuration;
+ var endMoveStartFrame = _startFrame;
+ var endMoveDuration = _durationFrames;
+ _startFrame = _startMoveStartFrame;
+ _durationFrames = _startMoveDuration;
+ using (new TrackUndoBlock(_tack))
+ {
+ _startFrame = endMoveStartFrame;
+ _durationFrames = endMoveDuration;
+ }
}
}
+ else
+ {
+ // Global timeline selection moving end
+ _timeline.OnKeyframesMove(null, this, _mouseLocation, false, true);
+ }
EndMouseCapture();
}
diff --git a/Source/Editor/GUI/Timeline/Timeline.cs b/Source/Editor/GUI/Timeline/Timeline.cs
index 0067d8010..d2ade10eb 100644
--- a/Source/Editor/GUI/Timeline/Timeline.cs
+++ b/Source/Editor/GUI/Timeline/Timeline.cs
@@ -219,6 +219,10 @@ namespace FlaxEditor.GUI.Timeline
private bool _isRightMouseButtonDown;
private Vector2 _rightMouseButtonDownPos;
private Vector2 _rightMouseButtonMovePos;
+ private Vector2 _mediaMoveStartPos;
+ private int[] _mediaMoveStartFrames;
+ private List