Implement a dialog for unsaved changes (#1241)

* Track unsaved scene changes

* Implement a dialog for unsaved changes

* Exclude all selection actions from scene change tracking
This commit is contained in:
Stanislav Denisov
2025-10-15 17:39:15 +02:00
committed by GitHub
parent 7318056235
commit a00fb8efc2
8 changed files with 190 additions and 16 deletions
+85 -6
View File
@@ -1294,7 +1294,15 @@ void EditorComponent::Load()
exitButton.SetTooltip("Exit");
exitButton.SetColor(wi::Color(160, 50, 50, 180), wi::gui::WIDGETSTATE::IDLE);
exitButton.SetColor(wi::Color(200, 50, 50, 255), wi::gui::WIDGETSTATE::FOCUS);
exitButton.OnClick([](wi::gui::EventArgs args) {
exitButton.OnClick([this](wi::gui::EventArgs args) {
// Check all scenes for unsaved changes
for (int i = 0; i < (int)scenes.size(); ++i)
{
if (!CheckUnsavedChanges(i))
{
return;
}
}
wi::platform::Exit();
});
topmenuWnd.AddWidget(&exitButton);
@@ -2350,7 +2358,7 @@ void EditorComponent::Update(float dt)
// Select...
if (leftmouse_select || selectAll || clear_selected)
{
wi::Archive& archive = AdvanceHistory();
wi::Archive& archive = AdvanceHistory(true);
archive << HISTORYOP_SELECTION;
// record PREVIOUS selection state...
RecordSelection(archive);
@@ -4735,8 +4743,9 @@ void EditorComponent::ResetHistory()
EditorScene& editorscene = GetCurrentEditorScene();
editorscene.historyPos = -1;
editorscene.history.clear();
editorscene.has_unsaved_changes = false;
}
wi::Archive& EditorComponent::AdvanceHistory()
wi::Archive& EditorComponent::AdvanceHistory(const bool scene_unchanged)
{
EditorScene& editorscene = GetCurrentEditorScene();
editorscene.historyPos++;
@@ -4749,6 +4758,12 @@ wi::Archive& EditorComponent::AdvanceHistory()
editorscene.history.emplace_back();
editorscene.history.back().SetReadModeAndResetPos(false);
if (!scene_unchanged)
{
editorscene.has_unsaved_changes = true;
RefreshSceneList();
}
return editorscene.history.back();
}
void EditorComponent::ConsumeHistoryOperation(bool undo)
@@ -5218,6 +5233,10 @@ void EditorComponent::Open(std::string filename)
componentsWnd.weatherWnd.UpdateData();
componentsWnd.RefreshEntityTree();
GetCurrentEditorScene().has_unsaved_changes = false;
RefreshSceneList();
wi::backlog::post("[Editor] finished loading model: " + filename);
});
});
@@ -5282,6 +5301,7 @@ void EditorComponent::Save(const std::string& filename)
}
GetCurrentEditorScene().path = filename;
GetCurrentEditorScene().has_unsaved_changes = false;
RefreshSceneList();
RegisterRecentlyUsed(filename);
@@ -5994,28 +6014,42 @@ void EditorComponent::RefreshSceneList()
for (int i = 0; i < int(scenes.size()); ++i)
{
auto& editorscene = scenes[i];
std::string tabText;
if (editorscene->path.empty())
{
if (current_localization.Get((size_t)EditorLocalization::UntitledScene))
{
editorscene->tabSelectButton.SetText(current_localization.Get((size_t)EditorLocalization::UntitledScene));
tabText = current_localization.Get((size_t)EditorLocalization::UntitledScene);
}
else
{
editorscene->tabSelectButton.SetText("Untitled scene");
tabText = "Untitled scene";
}
editorscene->tabSelectButton.SetTooltip("");
}
else
{
editorscene->tabSelectButton.SetText(wi::helper::GetFileNameFromPath(editorscene->path));
tabText = wi::helper::GetFileNameFromPath(editorscene->path);
editorscene->tabSelectButton.SetTooltip(editorscene->path);
}
if (editorscene->has_unsaved_changes)
{
tabText = tabText + " *";
}
editorscene->tabSelectButton.SetText(tabText);
editorscene->tabSelectButton.OnClick([this, i](wi::gui::EventArgs args) {
SetCurrentScene(i);
});
editorscene->tabCloseButton.OnClick([this, i](wi::gui::EventArgs args) {
// Check for unsaved changes before closing
if (!CheckUnsavedChanges(i))
{
return;
}
wi::lua::KillProcesses();
translator.selected.clear();
@@ -6090,6 +6124,51 @@ void EditorComponent::NewScene()
cameraWnd.ResetCam();
}
bool EditorComponent::CheckUnsavedChanges(int scene_index)
{
if (scene_index < 0)
scene_index = current_scene;
if (scene_index < 0 || scene_index >= (int)scenes.size())
return true;
EditorScene& editorscene = *scenes[scene_index];
if (!editorscene.has_unsaved_changes)
return true;
std::string sceneName = editorscene.path.empty() ? "" : wi::helper::GetFileNameFromPath(editorscene.path);
std::string message = sceneName.empty() ? "Do you want to save the untitled scene?" : "Do you want to save changes to \"" + sceneName + "\"?";
wi::helper::MessageBoxResult result = wi::helper::messageBoxCustom(message, "Unsaved changes", "YesNoCancel");
if (result == wi::helper::MessageBoxResult::Yes)
{
// User wants to save
if (editorscene.path.empty())
{
// Need to prompt for save location
SaveAs();
// After SaveAs, check if the scene was actually saved
return !editorscene.has_unsaved_changes;
}
else
{
// Save to existing path
Save(editorscene.path);
return true;
}
}
else if (result == wi::helper::MessageBoxResult::No)
{
// User doesn't want to save, proceed
return true;
}
else // Cancel or closed dialog
{
// User cancelled, don't proceed
return false;
}
}
void EditorComponent::FocusCameraOnSelected()
{
Scene& scene = GetCurrentScene();