From 3ea999245c0940f75c3300648276f3225b8a2126 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Fri, 20 Feb 2026 00:35:38 +0100 Subject: [PATCH 1/7] feat: Add a remove json button to the objects editor --- src/WeatherEditor/EditorWindow.cpp | 105 +++++++++++++++++++++++++++-- src/WeatherEditor/EditorWindow.h | 13 +++- src/WeatherEditor/Widget.cpp | 18 ++--- src/WeatherEditor/Widget.h | 3 +- 4 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 231e9e5f3d..ddf2d93e20 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -274,12 +274,13 @@ void EditorWindow::ShowObjectsWindow() } // Create a table for the right column with "Name" and "ID" headers. Different weights to prevent truncation. - if (ImGui::BeginTable("DetailsTable", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Sortable)) { - ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 25.0f); // Favorite indicator + if (ImGui::BeginTable("DetailsTable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Sortable)) { + ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 38.0f); // Favorite indicator ImGui::TableSetupColumn("Editor ID", ImGuiTableColumnFlags_WidthStretch, 3.5f); // Largest - weather/template names - ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 80.0f); // Fixed - 8 hex chars + ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 90.0f); // Fixed - 8 hex chars ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Medium - plugin names ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f); // Smaller - status text + ImGui::TableSetupColumn("json", ImGuiTableColumnFlags_WidthFixed, 55.0f); // JSON file / delete ImGui::TableHeadersRow(); @@ -313,6 +314,7 @@ void EditorWindow::ShowObjectsWindow() for (const auto& w : widgets) { sortedWidgets.push_back(w.get()); } + RefreshJsonAttachmentCache(sortedWidgets); if (currentSortColumn != SortColumn::None) { std::sort(sortedWidgets.begin(), sortedWidgets.end(), [this](Widget* a, Widget* b) { int comparison = 0; @@ -335,6 +337,13 @@ void EditorWindow::ShowObjectsWindow() comparison = _stricmp(statusA.c_str(), statusB.c_str()); break; } + case SortColumn::JsonAttachment: + { + bool aHasJson = HasCachedJsonAttachment(a); + bool bHasJson = HasCachedJsonAttachment(b); + comparison = static_cast(bHasJson) - static_cast(aHasJson); + break; + } default: break; } @@ -405,6 +414,9 @@ void EditorWindow::ShowObjectsWindow() // Status column ImGui::TableNextColumn(); ImGui::Text("Interior Cell"); + + // json column (empty for cells - no standalone json) + ImGui::TableNextColumn(); } else { // Show message that cell lighting is only for interior cells ImGui::TableNextRow(); @@ -467,7 +479,7 @@ void EditorWindow::ShowObjectsWindow() // Editor ID column with [CURRENT] prefix bool isSelected = sortedWidgets[i]->IsOpen(); - if (ImGui::Selectable(editorLabel.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { + if (ImGui::Selectable(editorLabel.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick | ImGuiSelectableFlags_AllowOverlap)) { if (ImGui::IsMouseDoubleClicked(0)) { sortedWidgets[i]->SetOpen(true); AddToRecent(sortedWidgets[i]->GetEditorID(), selectedCategory); @@ -512,6 +524,23 @@ void EditorWindow::ShowObjectsWindow() if (markedRecord != settings.markedRecords.end()) { ImGui::Text("%s", markedRecord->second.c_str()); } + + // json / delete column + ImGui::TableNextColumn(); + if (HasCachedJsonAttachment(sortedWidgets[i])) { + auto* menu = globals::menu; + if (menu && menu->uiIcons.deleteSettings.texture) { + const float iconSize = ImGui::GetFrameHeight() * 0.85f; + { + auto _style = Util::ErrorButtonStyle(); + ImGui::SetNextItemAllowOverlap(); + if (ImGui::ImageButton(std::format("##jsondel_cur_{}", sortedWidgets[i]->GetFormID()).c_str(), menu->uiIcons.deleteSettings.texture, { iconSize, iconSize })) + pendingDeleteWidget = sortedWidgets[i]; + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Delete json file"); + } + } } } @@ -555,7 +584,7 @@ void EditorWindow::ShowObjectsWindow() // Editor ID column bool isSelected = sortedWidgets[i]->IsOpen(); - if (ImGui::Selectable(editorLabel.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { + if (ImGui::Selectable(editorLabel.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick | ImGuiSelectableFlags_AllowOverlap)) { if (ImGui::IsMouseDoubleClicked(0)) { sortedWidgets[i]->SetOpen(true); AddToRecent(sortedWidgets[i]->GetEditorID(), selectedCategory); @@ -633,6 +662,23 @@ void EditorWindow::ShowObjectsWindow() if (markedRecord != settings.markedRecords.end()) { ImGui::Text("%s", markedRecord->second.c_str()); } + + // json / delete column + ImGui::TableNextColumn(); + if (HasCachedJsonAttachment(sortedWidgets[i])) { + auto* menu = globals::menu; + if (menu && menu->uiIcons.deleteSettings.texture) { + const float iconSize = ImGui::GetFrameHeight() * 0.85f; + { + auto _style = Util::ErrorButtonStyle(); + ImGui::SetNextItemAllowOverlap(); + if (ImGui::ImageButton(std::format("##jsondel_{}", sortedWidgets[i]->GetFormID()).c_str(), menu->uiIcons.deleteSettings.texture, { iconSize, iconSize })) + pendingDeleteWidget = sortedWidgets[i]; + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Delete json file"); + } + } } ImGui::EndTable(); // End DetailsTable @@ -644,6 +690,17 @@ void EditorWindow::ShowObjectsWindow() ImGui::EndTable(); // End ObjectTable } // End if BeginTable("ObjectTable") + // Confirmation modal for json deletion - must be outside BeginChild so the modal can block the root window + if (pendingDeleteWidget) { + auto* pendingWidget = pendingDeleteWidget; + ImGui::OpenPopup("ListDeleteConfirmation"); + pendingDeleteWidget->DrawDeleteConfirmationModal("ListDeleteConfirmation"); + if (!ImGui::IsPopupOpen("ListDeleteConfirmation")) { + InvalidateJsonAttachmentCache(pendingWidget); + pendingDeleteWidget = nullptr; + } + } + // End the window ImGui::End(); } @@ -1127,6 +1184,7 @@ void EditorWindow::SetupResources() { Load(); PaletteWindow::GetSingleton()->Load(); + InvalidateJsonAttachmentCache(); // Populate all widget collections using WidgetFactory templates WidgetFactory::PopulateWidgets(weatherWidgets); @@ -1776,6 +1834,43 @@ void EditorWindow::RenderNotifications() } } +void EditorWindow::RefreshJsonAttachmentCache(const std::vector& widgets) +{ + for (auto* widget : widgets) { + if (!widget) { + continue; + } + if (!jsonAttachmentCache.contains(widget)) { + jsonAttachmentCache.emplace(widget, widget->HasSavedFile()); + } + } +} + +bool EditorWindow::HasCachedJsonAttachment(Widget* widget) const +{ + if (!widget) { + return false; + } + if (auto it = jsonAttachmentCache.find(widget); it != jsonAttachmentCache.end()) { + return it->second; + } + return false; +} + +void EditorWindow::InvalidateJsonAttachmentCache(Widget* widget) +{ + if (widget) { + jsonAttachmentCache.erase(widget); + return; + } + jsonAttachmentCache.clear(); +} + +void EditorWindow::OnWidgetJsonAttachmentChanged(Widget* widget) +{ + InvalidateJsonAttachmentCache(widget); +} + void EditorWindow::AddToRecent(const std::string& widgetId, const std::string& category) { auto& categoryRecent = settings.recentWidgets[category]; diff --git a/src/WeatherEditor/EditorWindow.h b/src/WeatherEditor/EditorWindow.h index aab092977c..f159b9abbb 100644 --- a/src/WeatherEditor/EditorWindow.h +++ b/src/WeatherEditor/EditorWindow.h @@ -13,6 +13,8 @@ #include "WeatherUtils.h" #include "Widget.h" +#include + class EditorWindow { public: @@ -172,6 +174,7 @@ class EditorWindow void AddToRecent(const std::string& widgetId, const std::string& category); void ToggleFavorite(const std::string& widgetId); bool IsFavorite(const std::string& widgetId) const; + void OnWidgetJsonAttachmentChanged(Widget* widget); void SaveSessionWidgets(); void RestoreSessionWidgets(); @@ -208,8 +211,16 @@ class EditorWindow EditorID, FormID, File, - Status + Status, + JsonAttachment }; SortColumn currentSortColumn = SortColumn::None; bool sortAscending = true; + + Widget* pendingDeleteWidget = nullptr; + + std::unordered_map jsonAttachmentCache; + void RefreshJsonAttachmentCache(const std::vector& widgets); + bool HasCachedJsonAttachment(Widget* widget) const; + void InvalidateJsonAttachmentCache(Widget* widget = nullptr); }; \ No newline at end of file diff --git a/src/WeatherEditor/Widget.cpp b/src/WeatherEditor/Widget.cpp index 5583cfbabd..cc3d7cbee9 100644 --- a/src/WeatherEditor/Widget.cpp +++ b/src/WeatherEditor/Widget.cpp @@ -16,6 +16,7 @@ bool Widget::MatchesSearch(const std::string& text) const void Widget::Save() { + EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); SaveSettings(); const std::string filePath = std::format("{}\\{}", Util::PathHelpers::GetCommunityShaderPath().string(), GetFolderName()); const std::string file = std::format("{}\\{}.json", filePath, GetEditorID()); @@ -71,6 +72,7 @@ void Widget::Save() void Widget::Load() { + EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); std::string filePath = std::format("{}\\{}\\{}.json", Util::PathHelpers::GetCommunityShaderPath().string(), GetFolderName(), GetEditorID()); if (!std::filesystem::exists(filePath)) { @@ -145,6 +147,7 @@ void Widget::Load() void Widget::Delete() { + EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); std::string filePath = std::format("{}\\{}\\{}.json", Util::PathHelpers::GetCommunityShaderPath().string(), GetFolderName(), GetEditorID()); if (!std::filesystem::exists(filePath)) { @@ -202,14 +205,14 @@ void Widget::DrawMenu() DrawDeleteConfirmationModal(); } -void Widget::DrawDeleteConfirmationModal() +void Widget::DrawDeleteConfirmationModal(const char* popupId) { - if (!ImGui::IsPopupOpen("DeleteConfirmation")) + if (!ImGui::IsPopupOpen(popupId)) return; if (deleteConfirmationFrame == ImGui::GetFrameCount()) return; - if (ImGui::BeginPopupModal("DeleteConfirmation", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + if (ImGui::BeginPopupModal(popupId, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { deleteConfirmationFrame = ImGui::GetFrameCount(); ImGui::Text("Are you sure you want to delete the saved settings file?"); ImGui::Spacing(); @@ -345,12 +348,11 @@ void Widget::DrawWidgetHeader(const char* searchId, bool showApply, bool showSav if (HasSavedFile() && menu->uiIcons.deleteSettings.texture) { ImGui::SameLine(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.7f, 0.3f, 0.2f, 1.0f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.9f, 0.4f, 0.3f, 1.0f)); - if (ImGui::ImageButton((std::string(searchId) + "_Delete").c_str(), menu->uiIcons.deleteSettings.texture, buttonSize)) { - ImGui::OpenPopup("DeleteConfirmation"); + { + auto _style = Util::ErrorButtonStyle(); + if (ImGui::ImageButton((std::string(searchId) + "_Delete").c_str(), menu->uiIcons.deleteSettings.texture, buttonSize)) + ImGui::OpenPopup("DeleteConfirmation"); } - ImGui::PopStyleColor(2); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Delete saved file"); } diff --git a/src/WeatherEditor/Widget.h b/src/WeatherEditor/Widget.h index 9459eef518..596149bbfc 100644 --- a/src/WeatherEditor/Widget.h +++ b/src/WeatherEditor/Widget.h @@ -142,13 +142,14 @@ class Widget bool MatchesSearch(const std::string& text) const; + void DrawDeleteConfirmationModal(const char* popupId = "DeleteConfirmation"); + json js = json(); protected: std::string cachedEditorID; virtual void DrawMenu(); std::string GetFolderName(); - void DrawDeleteConfirmationModal(); }; // Simple widget for caching form data without full widget functionality From 2c32d6f1c406f9f500d044a96e97a85d0452c00a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 23:38:42 +0000 Subject: [PATCH 2/7] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commit.?= =?UTF-8?q?ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/WeatherEditor/EditorWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index ddf2d93e20..8dd9dbabc4 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -280,7 +280,7 @@ void EditorWindow::ShowObjectsWindow() ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 90.0f); // Fixed - 8 hex chars ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Medium - plugin names ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f); // Smaller - status text - ImGui::TableSetupColumn("json", ImGuiTableColumnFlags_WidthFixed, 55.0f); // JSON file / delete + ImGui::TableSetupColumn("json", ImGuiTableColumnFlags_WidthFixed, 55.0f); // JSON file / delete ImGui::TableHeadersRow(); From 6a418f20eb3ed2a0ff6cacb4082a842c2a439699 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Fri, 20 Feb 2026 01:00:13 +0100 Subject: [PATCH 3/7] fix: address comments --- src/WeatherEditor/EditorWindow.cpp | 68 +++++++++++++++--------------- src/WeatherEditor/EditorWindow.h | 5 ++- src/WeatherEditor/Widget.cpp | 6 +-- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 8dd9dbabc4..8d0a349720 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -289,7 +289,14 @@ void EditorWindow::ShowObjectsWindow() if (sortSpecs->SpecsDirty) { if (sortSpecs->SpecsCount > 0) { const ImGuiTableColumnSortSpecs& spec = sortSpecs->Specs[0]; - currentSortColumn = static_cast(spec.ColumnIndex); + switch (spec.ColumnIndex) { + case 1: currentSortColumn = SortColumn::EditorID; break; + case 2: currentSortColumn = SortColumn::FormID; break; + case 3: currentSortColumn = SortColumn::File; break; + case 4: currentSortColumn = SortColumn::Status; break; + case 5: currentSortColumn = SortColumn::JsonAttachment; break; + default: currentSortColumn = SortColumn::None; break; + } sortAscending = (spec.SortDirection == ImGuiSortDirection_Ascending); } else { currentSortColumn = SortColumn::None; @@ -341,7 +348,7 @@ void EditorWindow::ShowObjectsWindow() { bool aHasJson = HasCachedJsonAttachment(a); bool bHasJson = HasCachedJsonAttachment(b); - comparison = static_cast(bHasJson) - static_cast(aHasJson); + comparison = static_cast(aHasJson) - static_cast(bHasJson); break; } default: @@ -351,6 +358,25 @@ void EditorWindow::ShowObjectsWindow() }); } + // Helper lambda: renders the JSON delete button column for a widget + auto drawJsonDeleteButton = [&](Widget* widget) { + ImGui::TableNextColumn(); + if (HasCachedJsonAttachment(widget)) { + auto* menu = globals::menu; + if (menu && menu->uiIcons.deleteSettings.texture) { + const float iconSize = ImGui::GetFrameHeight() * 0.85f; + auto _style = Util::ErrorButtonStyle(); + ImGui::SetNextItemAllowOverlap(); + if (ImGui::ImageButton(std::format("##jsondel_{}", widget->GetFormID()).c_str(), menu->uiIcons.deleteSettings.texture, { iconSize, iconSize })) { + pendingDeleteWidget = widget; + pendingDeletePopupRequested = true; + } + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Delete JSON file"); + } + } + }; + // Special handling for Cell Lighting category if (selectedCategory == "Cell Lighting") { auto player = RE::PlayerCharacter::GetSingleton(); @@ -526,21 +552,7 @@ void EditorWindow::ShowObjectsWindow() } // json / delete column - ImGui::TableNextColumn(); - if (HasCachedJsonAttachment(sortedWidgets[i])) { - auto* menu = globals::menu; - if (menu && menu->uiIcons.deleteSettings.texture) { - const float iconSize = ImGui::GetFrameHeight() * 0.85f; - { - auto _style = Util::ErrorButtonStyle(); - ImGui::SetNextItemAllowOverlap(); - if (ImGui::ImageButton(std::format("##jsondel_cur_{}", sortedWidgets[i]->GetFormID()).c_str(), menu->uiIcons.deleteSettings.texture, { iconSize, iconSize })) - pendingDeleteWidget = sortedWidgets[i]; - } - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Delete json file"); - } - } + drawJsonDeleteButton(sortedWidgets[i]); } } @@ -664,21 +676,7 @@ void EditorWindow::ShowObjectsWindow() } // json / delete column - ImGui::TableNextColumn(); - if (HasCachedJsonAttachment(sortedWidgets[i])) { - auto* menu = globals::menu; - if (menu && menu->uiIcons.deleteSettings.texture) { - const float iconSize = ImGui::GetFrameHeight() * 0.85f; - { - auto _style = Util::ErrorButtonStyle(); - ImGui::SetNextItemAllowOverlap(); - if (ImGui::ImageButton(std::format("##jsondel_{}", sortedWidgets[i]->GetFormID()).c_str(), menu->uiIcons.deleteSettings.texture, { iconSize, iconSize })) - pendingDeleteWidget = sortedWidgets[i]; - } - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Delete json file"); - } - } + drawJsonDeleteButton(sortedWidgets[i]); } ImGui::EndTable(); // End DetailsTable @@ -693,10 +691,12 @@ void EditorWindow::ShowObjectsWindow() // Confirmation modal for json deletion - must be outside BeginChild so the modal can block the root window if (pendingDeleteWidget) { auto* pendingWidget = pendingDeleteWidget; - ImGui::OpenPopup("ListDeleteConfirmation"); + if (pendingDeletePopupRequested) { + ImGui::OpenPopup("ListDeleteConfirmation"); + pendingDeletePopupRequested = false; + } pendingDeleteWidget->DrawDeleteConfirmationModal("ListDeleteConfirmation"); if (!ImGui::IsPopupOpen("ListDeleteConfirmation")) { - InvalidateJsonAttachmentCache(pendingWidget); pendingDeleteWidget = nullptr; } } diff --git a/src/WeatherEditor/EditorWindow.h b/src/WeatherEditor/EditorWindow.h index f159b9abbb..788572d41f 100644 --- a/src/WeatherEditor/EditorWindow.h +++ b/src/WeatherEditor/EditorWindow.h @@ -174,7 +174,6 @@ class EditorWindow void AddToRecent(const std::string& widgetId, const std::string& category); void ToggleFavorite(const std::string& widgetId); bool IsFavorite(const std::string& widgetId) const; - void OnWidgetJsonAttachmentChanged(Widget* widget); void SaveSessionWidgets(); void RestoreSessionWidgets(); @@ -184,6 +183,8 @@ class EditorWindow ~EditorWindow(); private: + friend class Widget; + void SaveAll(); void SaveSettings(); void LoadSettings(); @@ -218,7 +219,9 @@ class EditorWindow bool sortAscending = true; Widget* pendingDeleteWidget = nullptr; + bool pendingDeletePopupRequested = false; + void OnWidgetJsonAttachmentChanged(Widget* widget); std::unordered_map jsonAttachmentCache; void RefreshJsonAttachmentCache(const std::vector& widgets); bool HasCachedJsonAttachment(Widget* widget) const; diff --git a/src/WeatherEditor/Widget.cpp b/src/WeatherEditor/Widget.cpp index cc3d7cbee9..958630d553 100644 --- a/src/WeatherEditor/Widget.cpp +++ b/src/WeatherEditor/Widget.cpp @@ -16,7 +16,6 @@ bool Widget::MatchesSearch(const std::string& text) const void Widget::Save() { - EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); SaveSettings(); const std::string filePath = std::format("{}\\{}", Util::PathHelpers::GetCommunityShaderPath().string(), GetFolderName()); const std::string file = std::format("{}\\{}.json", filePath, GetEditorID()); @@ -60,6 +59,7 @@ void Widget::Save() } settingsFile.close(); + EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); } catch (const nlohmann::json::exception& e) { logger::error("{}: JSON error while saving settings: {}", GetEditorID(), e.what()); @@ -72,7 +72,6 @@ void Widget::Save() void Widget::Load() { - EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); std::string filePath = std::format("{}\\{}\\{}.json", Util::PathHelpers::GetCommunityShaderPath().string(), GetFolderName(), GetEditorID()); if (!std::filesystem::exists(filePath)) { @@ -147,7 +146,6 @@ void Widget::Load() void Widget::Delete() { - EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); std::string filePath = std::format("{}\\{}\\{}.json", Util::PathHelpers::GetCommunityShaderPath().string(), GetFolderName(), GetEditorID()); if (!std::filesystem::exists(filePath)) { @@ -165,6 +163,8 @@ void Widget::Delete() // Apply the vanilla values to the game ApplyChanges(); + EditorWindow::GetSingleton()->OnWidgetJsonAttachmentChanged(this); + EditorWindow::GetSingleton()->ShowNotification( std::format("Deleted {} - reverted to vanilla values", GetEditorID()), ImVec4(0.0f, 1.0f, 0.0f, 1.0f), From 8cf9817cee29f2209c469e60ade499533d7c83d5 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Fri, 20 Feb 2026 01:00:49 +0100 Subject: [PATCH 4/7] fix: compile --- src/WeatherEditor/EditorWindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 8d0a349720..df9e3ddf1d 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -690,7 +690,6 @@ void EditorWindow::ShowObjectsWindow() // Confirmation modal for json deletion - must be outside BeginChild so the modal can block the root window if (pendingDeleteWidget) { - auto* pendingWidget = pendingDeleteWidget; if (pendingDeletePopupRequested) { ImGui::OpenPopup("ListDeleteConfirmation"); pendingDeletePopupRequested = false; From 45143c7f1bff712332753975549648dbc6734af9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 00:01:13 +0000 Subject: [PATCH 5/7] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commit.?= =?UTF-8?q?ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/WeatherEditor/EditorWindow.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index df9e3ddf1d..4b91a896bb 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -290,12 +290,24 @@ void EditorWindow::ShowObjectsWindow() if (sortSpecs->SpecsCount > 0) { const ImGuiTableColumnSortSpecs& spec = sortSpecs->Specs[0]; switch (spec.ColumnIndex) { - case 1: currentSortColumn = SortColumn::EditorID; break; - case 2: currentSortColumn = SortColumn::FormID; break; - case 3: currentSortColumn = SortColumn::File; break; - case 4: currentSortColumn = SortColumn::Status; break; - case 5: currentSortColumn = SortColumn::JsonAttachment; break; - default: currentSortColumn = SortColumn::None; break; + case 1: + currentSortColumn = SortColumn::EditorID; + break; + case 2: + currentSortColumn = SortColumn::FormID; + break; + case 3: + currentSortColumn = SortColumn::File; + break; + case 4: + currentSortColumn = SortColumn::Status; + break; + case 5: + currentSortColumn = SortColumn::JsonAttachment; + break; + default: + currentSortColumn = SortColumn::None; + break; } sortAscending = (spec.SortDirection == ImGuiSortDirection_Ascending); } else { From efe84527896e8a4864b8411ec588af7b720c8904 Mon Sep 17 00:00:00 2001 From: SkrubbySkrubInAShrub Date: Fri, 20 Feb 2026 11:52:00 +0100 Subject: [PATCH 6/7] fix: address ai --- src/WeatherEditor/EditorWindow.cpp | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 4b91a896bb..90eb66f789 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -273,14 +273,17 @@ void EditorWindow::ShowObjectsWindow() } } + // Stable user IDs for sortable columns — used instead of ColumnIndex so reordering/insertion won't break sorting. + enum ColumnID : ImGuiID { ColFav = 0, ColEditorID, ColFormID, ColFile, ColStatus, ColJson }; + // Create a table for the right column with "Name" and "ID" headers. Different weights to prevent truncation. if (ImGui::BeginTable("DetailsTable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Sortable)) { - ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 38.0f); // Favorite indicator - ImGui::TableSetupColumn("Editor ID", ImGuiTableColumnFlags_WidthStretch, 3.5f); // Largest - weather/template names - ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 90.0f); // Fixed - 8 hex chars - ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Medium - plugin names - ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f); // Smaller - status text - ImGui::TableSetupColumn("json", ImGuiTableColumnFlags_WidthFixed, 55.0f); // JSON file / delete + ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 38.0f, ColFav); // Favorite indicator + ImGui::TableSetupColumn("Editor ID", ImGuiTableColumnFlags_WidthStretch, 3.5f, ColEditorID); // Largest - weather/template names + ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 90.0f, ColFormID); // Fixed - 8 hex chars + ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f, ColFile); // Medium - plugin names + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f, ColStatus); // Smaller - status text + ImGui::TableSetupColumn("json", ImGuiTableColumnFlags_WidthFixed, 55.0f, ColJson); // JSON file / delete ImGui::TableHeadersRow(); @@ -289,20 +292,20 @@ void EditorWindow::ShowObjectsWindow() if (sortSpecs->SpecsDirty) { if (sortSpecs->SpecsCount > 0) { const ImGuiTableColumnSortSpecs& spec = sortSpecs->Specs[0]; - switch (spec.ColumnIndex) { - case 1: + switch (spec.ColumnUserID) { + case ColEditorID: currentSortColumn = SortColumn::EditorID; break; - case 2: + case ColFormID: currentSortColumn = SortColumn::FormID; break; - case 3: + case ColFile: currentSortColumn = SortColumn::File; break; - case 4: + case ColStatus: currentSortColumn = SortColumn::Status; break; - case 5: + case ColJson: currentSortColumn = SortColumn::JsonAttachment; break; default: @@ -379,7 +382,9 @@ void EditorWindow::ShowObjectsWindow() const float iconSize = ImGui::GetFrameHeight() * 0.85f; auto _style = Util::ErrorButtonStyle(); ImGui::SetNextItemAllowOverlap(); - if (ImGui::ImageButton(std::format("##jsondel_{}", widget->GetFormID()).c_str(), menu->uiIcons.deleteSettings.texture, { iconSize, iconSize })) { + char idBuf[32]; + snprintf(idBuf, sizeof(idBuf), "##jsondel_%s", widget->GetFormID().c_str()); + if (ImGui::ImageButton(idBuf, menu->uiIcons.deleteSettings.texture, { iconSize, iconSize })) { pendingDeleteWidget = widget; pendingDeletePopupRequested = true; } From ab9796888bf9d84ae71e0ca84adb4315e6449c12 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 10:52:25 +0000 Subject: [PATCH 7/7] =?UTF-8?q?style:=20=F0=9F=8E=A8=20apply=20pre-commit.?= =?UTF-8?q?ci=20formatting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated formatting by clang-format, prettier, and other hooks. See https://pre-commit.ci for details. --- src/WeatherEditor/EditorWindow.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/WeatherEditor/EditorWindow.cpp b/src/WeatherEditor/EditorWindow.cpp index 90eb66f789..9f06f2077a 100644 --- a/src/WeatherEditor/EditorWindow.cpp +++ b/src/WeatherEditor/EditorWindow.cpp @@ -274,16 +274,24 @@ void EditorWindow::ShowObjectsWindow() } // Stable user IDs for sortable columns — used instead of ColumnIndex so reordering/insertion won't break sorting. - enum ColumnID : ImGuiID { ColFav = 0, ColEditorID, ColFormID, ColFile, ColStatus, ColJson }; + enum ColumnID : ImGuiID + { + ColFav = 0, + ColEditorID, + ColFormID, + ColFile, + ColStatus, + ColJson + }; // Create a table for the right column with "Name" and "ID" headers. Different weights to prevent truncation. if (ImGui::BeginTable("DetailsTable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Sortable)) { - ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 38.0f, ColFav); // Favorite indicator - ImGui::TableSetupColumn("Editor ID", ImGuiTableColumnFlags_WidthStretch, 3.5f, ColEditorID); // Largest - weather/template names - ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 90.0f, ColFormID); // Fixed - 8 hex chars - ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f, ColFile); // Medium - plugin names - ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f, ColStatus); // Smaller - status text - ImGui::TableSetupColumn("json", ImGuiTableColumnFlags_WidthFixed, 55.0f, ColJson); // JSON file / delete + ImGui::TableSetupColumn("Fav", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoSort, 38.0f, ColFav); // Favorite indicator + ImGui::TableSetupColumn("Editor ID", ImGuiTableColumnFlags_WidthStretch, 3.5f, ColEditorID); // Largest - weather/template names + ImGui::TableSetupColumn("Form ID", ImGuiTableColumnFlags_WidthFixed, 90.0f, ColFormID); // Fixed - 8 hex chars + ImGui::TableSetupColumn("File", ImGuiTableColumnFlags_WidthStretch, 2.0f, ColFile); // Medium - plugin names + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthStretch, 1.5f, ColStatus); // Smaller - status text + ImGui::TableSetupColumn("json", ImGuiTableColumnFlags_WidthFixed, 55.0f, ColJson); // JSON file / delete ImGui::TableHeadersRow();