diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 13b748d94..0b85fbdad 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -9,6 +9,7 @@ using FlaxEditor.Content; using FlaxEditor.Content.Import; using FlaxEditor.Content.Settings; using FlaxEditor.Content.Thumbnails; +using FlaxEditor.GUI; using FlaxEditor.Modules; using FlaxEditor.Modules.SourceCodeEditing; using FlaxEditor.Options; @@ -46,6 +47,8 @@ namespace FlaxEditor private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode; private string _projectToOpen; private float _lastAutoSaveTimer; + private AutoSavePopup _autoSavePopup; + private bool _autoSaveNow; private Guid _startupSceneCmdLine; private const string ProjectDataLastScene = "LastScene"; @@ -491,7 +494,28 @@ namespace FlaxEditor var timeToNextSave = options.AutoSaveFrequency * 60.0f - timeSinceLastSave; var countDownDuration = 4.0f; - if (timeToNextSave <= 0.0f) + // Show auto save popup + if (timeToNextSave <= options.AutoSaveReminderTime && timeToNextSave >= 0) + { + if (_autoSavePopup == null) + { + _autoSavePopup = AutoSavePopup.Show(Instance.Windows.MainWindow.GUI, timeToNextSave); + _autoSavePopup.SaveNowButton.Clicked += () => _autoSaveNow = true; + _autoSavePopup.CancelSaveButton.Clicked += () => + { + Log("Auto save canceled"); + _autoSavePopup.HidePopup(); + _lastAutoSaveTimer = Time.UnscaledGameTime; // Reset timer + }; + } + else if (!_autoSavePopup.Visible && !_autoSavePopup.UserClosed) + _autoSavePopup.ShowPopup(); + + if (_autoSavePopup.Visible) + _autoSavePopup.UpdateTime(timeToNextSave); + } + + if (timeToNextSave <= 0.0f || _autoSaveNow) { Log("Auto save"); _lastAutoSaveTimer = Time.UnscaledGameTime; @@ -499,6 +523,11 @@ namespace FlaxEditor Scene.SaveScenes(); if (options.AutoSaveContent) SaveContent(); + + // Hide auto save popup and reset user closed + _autoSavePopup.HidePopup(); + _autoSavePopup.UserClosed = false; + _autoSaveNow = false; } else if (timeToNextSave < countDownDuration) { diff --git a/Source/Editor/GUI/Popups/AutoSavePopup.cs b/Source/Editor/GUI/Popups/AutoSavePopup.cs new file mode 100644 index 000000000..28f9577d8 --- /dev/null +++ b/Source/Editor/GUI/Popups/AutoSavePopup.cs @@ -0,0 +1,169 @@ +using FlaxEngine; +using FlaxEngine.GUI; + +namespace FlaxEditor.GUI +{ + /// + /// Popup menu for reminding of an upcoming auto save. + /// + public class AutoSavePopup : ContainerControl + { + /// + /// Gets or sets the value for if the user has manually closed this popup. + /// + public bool UserClosed { get; set; } + + /// + /// The save now button. Used to skip the last remaining auto save time. + /// + public Button SaveNowButton => _saveNowButton; + + /// + /// Button that should be used to cancel the auto save. + /// + public Button CancelSaveButton => _cancelSaveButton; + + private int _timeRemaining; + private Panel _backgroundPanel; + private Label _timeLabel; + private Button _saveNowButton; + private Button _cancelSaveButton; + private Color _defaultTextColor; + private bool _isMoved = false; + + /// + /// Initialize the AutoSavePopup. + /// + /// The initial time to set the time label to. + public AutoSavePopup(float initialTime) + { + UpdateTime(initialTime); + + _backgroundPanel = new Panel(ScrollBars.None) + { + Parent = this, + AnchorPreset = AnchorPresets.StretchAll, + BackgroundColor = Color.Transparent, + }; + + _timeLabel = new Label(0, 0, 25, 10) + { + Parent = _backgroundPanel, + Text = _timeRemaining.ToString(), + HorizontalAlignment = TextAlignment.Near, + VerticalAlignment = TextAlignment.Near, + AutoWidth = true, + Height = 14, + AnchorPreset = AnchorPresets.MiddleLeft, + }; + + _saveNowButton = new Button + { + Parent = _backgroundPanel, + Height = 14, + Width = 60, + AnchorPreset = AnchorPresets.MiddleRight, + BackgroundColor = Color.Transparent, + BorderColor = Color.Transparent, + BackgroundColorHighlighted = Color.Transparent, + BackgroundColorSelected = Color.Transparent, + BorderColorHighlighted = Color.Transparent, + Text = "Save Now", + TooltipText = "Saves now and restarts the auto save timer." + }; + _saveNowButton.LocalX -= 85; + + _cancelSaveButton = new Button + { + Parent = _backgroundPanel, + Height = 14, + Width = 70, + AnchorPreset = AnchorPresets.MiddleRight, + BackgroundColor = Color.Transparent, + BorderColor = Color.Transparent, + BackgroundColorHighlighted = Color.Transparent, + BackgroundColorSelected = Color.Transparent, + BorderColorHighlighted = Color.Transparent, + Text = "Cancel Save", + TooltipText = "Cancels this auto save." + }; + _cancelSaveButton.LocalX -= 5; + + _defaultTextColor = _saveNowButton.TextColor; + } + + /// + /// Updates the time label + /// + /// The time to change the label to. + public void UpdateTime(float time) + { + _timeRemaining = Mathf.CeilToInt(time); + if (_timeLabel != null) + _timeLabel.Text = "Auto Save in: " + _timeRemaining; + + // Move on text update if the progress bar is visible - removes this call from update + if (Editor.Instance.UI.ProgressVisible && !_isMoved) + { + _isMoved = true; + LocalX -= 250; + } + else if (!Editor.Instance.UI.ProgressVisible && _isMoved) + { + LocalX += 250; + _isMoved = false; + } + } + + /// + public override void Update(float deltaTime) + { + if (IsMouseOver) + { + _saveNowButton.TextColor = _saveNowButton.IsMouseOver ? Style.Current.BackgroundHighlighted : _defaultTextColor; + _cancelSaveButton.TextColor = _cancelSaveButton.IsMouseOver ? Style.Current.BackgroundHighlighted : _defaultTextColor; + } + base.Update(deltaTime); + } + + /// + /// Creates and shows the AutoSavePopup + /// + /// The parent control. + /// The time to start at. + /// + public static AutoSavePopup Show(ContainerControl parentControl, float initialTime) + { + var popup = new AutoSavePopup(initialTime) + { + Parent = parentControl, + Height = Editor.Instance.UI.StatusBar.Height, + Width = 250, + AnchorPreset = AnchorPresets.BottomRight, + }; + popup.ShowPopup(); + return popup; + } + + /// + /// Shows the popup by changing its visibility + /// + public void ShowPopup() + { + Visible = true; + UserClosed = false; + _saveNowButton.TextColor = _defaultTextColor; + _cancelSaveButton.TextColor = _defaultTextColor; + } + + /// + /// Hides the popup by changing its visibility + /// + public void HidePopup() + { + Visible = false; + if (_containsFocus) + Defocus(); + } + } +} diff --git a/Source/Editor/Options/GeneralOptions.cs b/Source/Editor/Options/GeneralOptions.cs index 814e80d0a..b02af39cf 100644 --- a/Source/Editor/Options/GeneralOptions.cs +++ b/Source/Editor/Options/GeneralOptions.cs @@ -189,19 +189,26 @@ namespace FlaxEditor.Options [DefaultValue(5), Limit(1)] [EditorDisplay("Auto Save", "Auto Save Frequency"), EditorOrder(801), Tooltip("The interval between auto saves (in minutes)")] public int AutoSaveFrequency { get; set; } = 5; + + /// + /// Gets or sets a value indicating the time before the auto save that the popup shows (in seconds). + /// + [DefaultValue(10), Limit(-1)] + [EditorDisplay("Auto Save", "Auto Save Reminder Time"), EditorOrder(802), Tooltip("The time before the auto save that the reminder popup shows (in seconds). Set to -1 to not show the reminder popup.")] + public int AutoSaveReminderTime { get; set; } = 10; /// /// Gets or sets a value indicating whether enable auto saves for scenes. /// [DefaultValue(true)] - [EditorDisplay("Auto Save", "Auto Save Scenes"), EditorOrder(802), Tooltip("Enables or disables auto saving opened scenes")] + [EditorDisplay("Auto Save", "Auto Save Scenes"), EditorOrder(803), Tooltip("Enables or disables auto saving opened scenes")] public bool AutoSaveScenes { get; set; } = true; /// /// Gets or sets a value indicating whether enable auto saves for content. /// [DefaultValue(true)] - [EditorDisplay("Auto Save", "Auto Save Content"), EditorOrder(803), Tooltip("Enables or disables auto saving content")] + [EditorDisplay("Auto Save", "Auto Save Content"), EditorOrder(804), Tooltip("Enables or disables auto saving content")] public bool AutoSaveContent { get; set; } = true; ///